From: Robert Varga Date: Wed, 31 Jan 2024 21:56:33 +0000 (+0100) Subject: Expose NetconfKeystoreService X-Git-Tag: v7.0.0~64 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=6aba89d85fae22bb93e52e2359b232f6f526b29e;p=netconf.git Expose NetconfKeystoreService We are performing translation of datastore configuration state into Java equivalent. Let's expose that as a service and run a full component, which supports asynchronous updates. This also defers start by not reporting initial state until we have observed the datastore. JIRA: NETCONF-1237 Change-Id: Ib6b34d707eb664a94cb4a30049e50444f47fc5ae Signed-off-by: Robert Varga --- diff --git a/keystore/keystore-legacy/pom.xml b/keystore/keystore-legacy/pom.xml index 94f2b5a5df..209a25ea72 100644 --- a/keystore/keystore-legacy/pom.xml +++ b/keystore/keystore-legacy/pom.xml @@ -22,6 +22,17 @@ Legacy NETCONF keystore + + com.guicedee.services + javax.inject + true + + + jakarta.annotation + jakarta.annotation-api + provided + true + org.opendaylight.aaa aaa-encrypt-service @@ -42,6 +53,10 @@ org.opendaylight.yangtools concepts + + org.osgi + org.osgi.service.component.annotations + org.opendaylight.netconf @@ -49,4 +64,18 @@ test + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.netconf.keystore.legacy + + + + + diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/CertifiedPrivateKey.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/CertifiedPrivateKey.java new file mode 100644 index 0000000000..e350153239 --- /dev/null +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/CertifiedPrivateKey.java @@ -0,0 +1,29 @@ +/* + * 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 java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.List; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Immutable; + +@NonNullByDefault +public record CertifiedPrivateKey( + PrivateKey key, + List certificateChain) implements Immutable { + public CertifiedPrivateKey { + requireNonNull(key); + certificateChain = List.copyOf(certificateChain); + if (certificateChain.isEmpty()) { + throw new IllegalArgumentException("Certificate chain must not be empty"); + } + } +} \ No newline at end of file diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystore.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystore.java new file mode 100644 index 0000000000..0f04c0b6eb --- /dev/null +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystore.java @@ -0,0 +1,25 @@ +/* + * 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 java.security.cert.X509Certificate; +import java.util.Map; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Immutable; + +@NonNullByDefault +public record NetconfKeystore( + Map privateKeys, + Map trustedCertificates) implements Immutable { + public static final NetconfKeystore EMPTY = new NetconfKeystore(Map.of(), Map.of()); + + public NetconfKeystore { + privateKeys = Map.copyOf(privateKeys); + trustedCertificates = Map.copyOf(trustedCertificates); + } +} diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreService.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreService.java new file mode 100644 index 0000000000..11c1b0cb57 --- /dev/null +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreService.java @@ -0,0 +1,21 @@ +/* + * 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 java.util.function.Consumer; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Registration; + +/** + * Asynchronous access to {@link NetconfKeystore}. + */ +@NonNullByDefault +public interface NetconfKeystoreService { + + Registration registerKeystoreConsumer(Consumer consumer); +} diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractRpc.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/AbstractRpc.java similarity index 93% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractRpc.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/AbstractRpc.java index b2db630f36..920ca6c6dc 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractRpc.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/AbstractRpc.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static java.util.Objects.requireNonNull; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/ConfigListener.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/ConfigListener.java similarity index 92% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/ConfigListener.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/ConfigListener.java index 35d3c45939..cc1f9e1c5b 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/ConfigListener.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/ConfigListener.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static java.util.Objects.requireNonNull; @@ -14,7 +14,7 @@ import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; import org.opendaylight.mdsal.binding.api.DataTreeModification; -import org.opendaylight.netconf.keystore.legacy.AbstractNetconfKeystore.ConfigStateBuilder; +import org.opendaylight.netconf.keystore.legacy.impl.DefaultNetconfKeystoreService.ConfigStateBuilder; 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; @@ -22,7 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; @NonNullByDefault -record ConfigListener(AbstractNetconfKeystore keystore) implements DataTreeChangeListener { +record ConfigListener(DefaultNetconfKeystoreService keystore) implements DataTreeChangeListener { private static final Logger LOG = LoggerFactory.getLogger(ConfigListener.class); ConfigListener { diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddKeystoreEntry.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddKeystoreEntry.java similarity index 98% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddKeystoreEntry.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddKeystoreEntry.java index 828ebaf246..d40e02a258 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddKeystoreEntry.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddKeystoreEntry.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static java.util.Objects.requireNonNull; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddPrivateKey.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddPrivateKey.java similarity index 97% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddPrivateKey.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddPrivateKey.java index a8e4251f8c..f3dfc18611 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddPrivateKey.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddPrivateKey.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddTrustedCertificate.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddTrustedCertificate.java similarity index 97% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddTrustedCertificate.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddTrustedCertificate.java index 795aeda223..2e433369cc 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultAddTrustedCertificate.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultAddTrustedCertificate.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractNetconfKeystore.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultNetconfKeystoreService.java similarity index 69% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractNetconfKeystore.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultNetconfKeystoreService.java index d06a62a34e..815280f48a 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/AbstractNetconfKeystore.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultNetconfKeystoreService.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static java.util.Objects.requireNonNull; @@ -16,10 +16,14 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Base64; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -29,45 +33,31 @@ 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.netconf.keystore.legacy.CertifiedPrivateKey; +import org.opendaylight.netconf.keystore.legacy.NetconfKeystore; +import org.opendaylight.netconf.keystore.legacy.NetconfKeystoreService; 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; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.concepts.Mutable; +import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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; /** * Abstract substrate for implementing security services based on the contents of {@link Keystore}. */ -public abstract class AbstractNetconfKeystore { - @NonNullByDefault - protected record CertifiedPrivateKey( - java.security.PrivateKey key, - List certificateChain) implements Immutable { - public CertifiedPrivateKey { - requireNonNull(key); - certificateChain = List.copyOf(certificateChain); - if (certificateChain.isEmpty()) { - throw new IllegalArgumentException("Certificate chain must not be empty"); - } - } - } - - @NonNullByDefault - protected record State( - Map privateKeys, - Map trustedCertificates) implements Immutable { - public static final State EMPTY = new State(Map.of(), Map.of()); - - public State { - privateKeys = Map.copyOf(privateKeys); - trustedCertificates = Map.copyOf(trustedCertificates); - } - } - +@Singleton +@Component(service = NetconfKeystoreService.class) +public final class DefaultNetconfKeystoreService implements NetconfKeystoreService, AutoCloseable { @NonNullByDefault private record ConfigState( Map privateKeys, @@ -90,48 +80,60 @@ public abstract class AbstractNetconfKeystore { } } - private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfKeystore.class); + private static final Logger LOG = LoggerFactory.getLogger(DefaultNetconfKeystoreService.class); - private final AtomicReference<@NonNull ConfigState> state = new AtomicReference<>(ConfigState.EMPTY); + private final Set>> consumers = ConcurrentHashMap.newKeySet(); + private final AtomicReference keystore = new AtomicReference<>(null); + private final AtomicReference config = new AtomicReference<>(ConfigState.EMPTY); private final SecurityHelper securityHelper = new SecurityHelper(); + private final Registration configListener; + private final Registration rpcSingleton; + + @Inject + @Activate + public DefaultNetconfKeystoreService(@Reference final DataBroker dataBroker, + @Reference final RpcProviderService rpcProvider, + @Reference final ClusterSingletonServiceProvider cssProvider, + @Reference final AAAEncryptionService encryptionService) { + configListener = dataBroker.registerTreeChangeListener( + DataTreeIdentifier.of(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Keystore.class)), + new ConfigListener(this)); + rpcSingleton = cssProvider.registerClusterSingletonService( + new RpcSingleton(dataBroker, rpcProvider, encryptionService)); + + // FIXME: create an operation datastore updater and register it as a consumer - private @Nullable Registration configListener; - private @Nullable Registration rpcSingleton; - - 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; - listener.close(); - state.set(ConfigState.EMPTY); - } + @PreDestroy + @Deactivate + @Override + public void close() { + rpcSingleton.close(); + configListener.close(); + LOG.info("NETCONF keystore service stopped"); } - protected abstract void onStateUpdated(@NonNull State newState); + @Override + public Registration registerKeystoreConsumer(final Consumer consumer) { + final var reg = new AbstractObjectRegistration<>(consumer) { + @Override + protected void removeRegistration() { + consumers.remove(this); + } + }; - final void runUpdate(final Consumer<@NonNull ConfigStateBuilder> task) { - final var prevState = state.getAcquire(); + consumers.add(reg); + final var ks = keystore.getAcquire(); + if (ks != null) { + consumer.accept(ks); + } + return reg; + } + + void runUpdate(final Consumer<@NonNull ConfigStateBuilder> task) { + final var prevState = config.getAcquire(); final var builder = new ConfigStateBuilder(new HashMap<>(prevState.privateKeys), new HashMap<>(prevState.trustedCertificates)); @@ -139,7 +141,7 @@ public abstract class AbstractNetconfKeystore { final var newState = new ConfigState(builder.privateKeys, builder.trustedCertificates); // Careful application -- check if listener is still up and whether the state was not updated. - if (configListener == null || state.compareAndExchangeRelease(prevState, newState) != prevState) { + if (configListener == null || config.compareAndExchangeRelease(prevState, newState) != prevState) { return; } @@ -231,9 +233,9 @@ public abstract class AbstractNetconfKeystore { return; } - onStateUpdated(new State(keys, certs)); - - // FIXME: tickle operational updater (which does not exist yet) + final var newKeystore = new NetconfKeystore(keys, certs); + keystore.setRelease(newKeystore); + consumers.forEach(consumer -> consumer.getInstance().accept(newKeystore)); } private static byte[] base64Decode(final String base64) { diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveKeystoreEntry.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveKeystoreEntry.java similarity index 98% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveKeystoreEntry.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveKeystoreEntry.java index d9c53b62f8..b7b1bba8c1 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveKeystoreEntry.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveKeystoreEntry.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemovePrivateKey.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemovePrivateKey.java similarity index 98% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemovePrivateKey.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemovePrivateKey.java index 04a3dbd9f0..7d3e7d6557 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemovePrivateKey.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemovePrivateKey.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveTrustedCertificate.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveTrustedCertificate.java similarity index 98% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveTrustedCertificate.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveTrustedCertificate.java index a95d9dee2d..292fb19cad 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/DefaultRemoveTrustedCertificate.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/DefaultRemoveTrustedCertificate.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/RpcSingleton.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/RpcSingleton.java similarity index 98% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/RpcSingleton.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/RpcSingleton.java index e49c714245..08b1079d3d 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/RpcSingleton.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/RpcSingleton.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static java.util.Objects.requireNonNull; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/SecurityHelper.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/SecurityHelper.java similarity index 97% rename from keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/SecurityHelper.java rename to keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/SecurityHelper.java index 18b3b547da..679970e99d 100644 --- a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/SecurityHelper.java +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/SecurityHelper.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import java.io.ByteArrayInputStream; import java.security.GeneralSecurityException; diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/package-info.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/package-info.java new file mode 100644 index 0000000000..3524f77cfd --- /dev/null +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/impl/package-info.java @@ -0,0 +1,11 @@ +/* + * 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 + */ +/** + * Implementation details. + */ +package org.opendaylight.netconf.keystore.legacy.impl; \ No newline at end of file diff --git a/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/package-info.java b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/package-info.java new file mode 100644 index 0000000000..8ed81de1b8 --- /dev/null +++ b/keystore/keystore-legacy/src/main/java/org/opendaylight/netconf/keystore/legacy/package-info.java @@ -0,0 +1,14 @@ +/* + * 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 + */ +/** + * Access to key and trust material stored in + * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.NetconfKeystoreData}. + * The primary access interface is {@link NetconfKeystoreService}, which allows subscription to receive updates about + * {@link NetconfKeystore}. + */ +package org.opendaylight.netconf.keystore.legacy; \ No newline at end of file diff --git a/keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreRpcsTest.java b/keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/impl/NetconfKeystoreRpcsTest.java similarity index 99% rename from keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreRpcsTest.java rename to keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/impl/NetconfKeystoreRpcsTest.java index 5396420339..1b1e845da8 100644 --- a/keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/NetconfKeystoreRpcsTest.java +++ b/keystore/keystore-legacy/src/test/java/org/opendaylight/netconf/keystore/legacy/impl/NetconfKeystoreRpcsTest.java @@ -5,7 +5,7 @@ * 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; +package org.opendaylight.netconf.keystore.legacy.impl; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; diff --git a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProvider.java b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProvider.java index 106b8c8b0c..0d98fa0bb0 100644 --- a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProvider.java +++ b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProvider.java @@ -19,15 +19,13 @@ import javax.annotation.PreDestroy; 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; +import org.opendaylight.netconf.keystore.legacy.NetconfKeystore; +import org.opendaylight.netconf.keystore.legacy.NetconfKeystoreService; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.parameters.protocol.Specification; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.parameters.protocol.specification.TlsCase; +import org.opendaylight.yangtools.concepts.Registration; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; @@ -35,34 +33,30 @@ import org.osgi.service.component.annotations.Reference; @Singleton @Component(service = SslHandlerFactoryProvider.class) -public final class DefaultSslHandlerFactoryProvider extends AbstractNetconfKeystore - implements SslHandlerFactoryProvider, AutoCloseable { +public final class DefaultSslHandlerFactoryProvider implements SslHandlerFactoryProvider, AutoCloseable { private static final X509Certificate[] EMPTY_CERTS = { }; private static final char[] EMPTY_CHARS = { }; private final @NonNull SslHandlerFactory nospecFactory = new SslHandlerFactoryImpl(this, Set.of()); + private final Registration reg; - private volatile @NonNull State state = State.EMPTY; + private volatile @NonNull NetconfKeystore keystore = NetconfKeystore.EMPTY; @Inject @Activate - public DefaultSslHandlerFactoryProvider(@Reference final DataBroker dataBroker, - @Reference final RpcProviderService rpcProvider, - @Reference final ClusterSingletonServiceProvider cssProvider, - @Reference final AAAEncryptionService encryptionService) { - start(dataBroker, rpcProvider, cssProvider, encryptionService); + public DefaultSslHandlerFactoryProvider(@Reference final NetconfKeystoreService keystoreService) { + reg = keystoreService.registerKeystoreConsumer(this::onKeystoreUpdated); } - @Deactivate - @PreDestroy @Override + @PreDestroy + @Deactivate public void close() { - stop(); + reg.close(); } - @Override - protected void onStateUpdated(final State newState) { - state = newState; + private void onKeystoreUpdated(final @NonNull NetconfKeystore newKeystore) { + keystore = newKeystore; } @Override @@ -91,7 +85,7 @@ public final class DefaultSslHandlerFactoryProvider extends AbstractNetconfKeyst */ KeyStore getJavaKeyStore(final Set allowedKeys) throws GeneralSecurityException, IOException { requireNonNull(allowedKeys); - final var current = state; + final var current = keystore; if (current.privateKeys().isEmpty()) { throw new KeyStoreException("No keystore private key found"); } diff --git a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProviderTest.java b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProviderTest.java index c20414ec3b..5f37ba205e 100644 --- a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProviderTest.java +++ b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/impl/DefaultSslHandlerFactoryProviderTest.java @@ -19,6 +19,7 @@ import java.security.KeyStoreException; import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,6 +33,7 @@ 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.netconf.keystore.legacy.impl.DefaultNetconfKeystoreService; 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._private.keys.PrivateKeyBuilder; @@ -61,7 +63,7 @@ class DefaultSslHandlerFactoryProviderTest { @Mock private AAAEncryptionService encryptionService; @Mock - private Registration listenerRegistration; + private Registration registration; @Mock private DataTreeModification dataTreeModification1; @Mock @@ -76,17 +78,25 @@ class DefaultSslHandlerFactoryProviderTest { private DataObjectModification trustedCertificateModification; private DataTreeChangeListener listener; + private DefaultNetconfKeystoreService keystore; @BeforeEach void beforeEach() { doAnswer(inv -> { listener = inv.getArgument(1); - return listenerRegistration; + return registration; }).when(dataBroker).registerTreeChangeListener(any(), any()); + doReturn(registration).when(cssProvider).registerClusterSingletonService(any()); + keystore = new DefaultNetconfKeystoreService(dataBroker, rpcProvider, cssProvider, encryptionService); + } + + @AfterEach + void afterEach() { + keystore.close(); } private DefaultSslHandlerFactoryProvider newProvider() { - return new DefaultSslHandlerFactoryProvider(dataBroker, rpcProvider, cssProvider, encryptionService); + return new DefaultSslHandlerFactoryProvider(keystore); } @Test