Skip to content

Commit ba5b31b

Browse files
committed
Do not depend on lighty-aaa module
The point of this rework is to not rely on other lighty modules to run gnmi. Let's rather use what is available from opendaylight instead.
1 parent 353d12e commit ba5b31b

File tree

5 files changed

+75
-77
lines changed

5 files changed

+75
-77
lines changed

lighty-modules/lighty-gnmi/lighty-gnmi-sb/pom.xml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@
7878
<artifactId>jsonassert</artifactId>
7979
<scope>test</scope>
8080
</dependency>
81-
<dependency>
82-
<groupId>io.lighty.modules</groupId>
83-
<artifactId>lighty-aaa-encryption-service</artifactId>
84-
<scope>test</scope>
85-
</dependency>
8681
<dependency>
8782
<groupId>org.mockito</groupId>
8883
<artifactId>mockito-subclass</artifactId>
@@ -103,10 +98,6 @@
10398
<artifactId>aaa-encrypt-service-impl</artifactId>
10499
<scope>test</scope>
105100
</dependency>
106-
<dependency>
107-
<groupId>io.lighty.modules</groupId>
108-
<artifactId>lighty-aaa</artifactId>
109-
</dependency>
110101
</dependencies>
111102

112103
</project>

lighty-modules/lighty-gnmi/lighty-gnmi-sb/src/main/java/io/lighty/gnmi/southbound/device/session/security/KeystoreGnmiSecurityProvider.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,28 @@
88

99
package io.lighty.gnmi.southbound.device.session.security;
1010

11-
import io.lighty.aaa.util.AAAConfigUtils;
1211
import io.lighty.gnmi.southbound.schema.certstore.service.CertificationStorageService;
1312
import io.lighty.gnmi.southbound.timeout.TimeoutUtils;
1413
import io.lighty.modules.gnmi.connector.configuration.SecurityFactory;
1514
import io.lighty.modules.gnmi.connector.security.Security;
1615
import java.io.IOException;
16+
import java.io.Reader;
1717
import java.io.StringReader;
1818
import java.security.GeneralSecurityException;
1919
import java.security.KeyPair;
20+
import java.security.Provider;
2021
import java.security.cert.CertificateException;
2122
import java.util.Optional;
2223
import java.util.concurrent.ExecutionException;
2324
import java.util.concurrent.TimeUnit;
2425
import java.util.concurrent.TimeoutException;
26+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
27+
import org.bouncycastle.openssl.PEMDecryptorProvider;
28+
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
29+
import org.bouncycastle.openssl.PEMKeyPair;
30+
import org.bouncycastle.openssl.PEMParser;
31+
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
32+
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
2533
import org.opendaylight.yang.gen.v1.urn.lighty.gnmi.certificate.storage.rev210504.Keystore;
2634
import org.opendaylight.yang.gen.v1.urn.lighty.gnmi.topology.rev210316.GnmiNode;
2735
import org.opendaylight.yang.gen.v1.urn.lighty.gnmi.topology.rev210316.security.SecurityChoice;
@@ -100,7 +108,7 @@ private Security createSecurityFromKeystore(final KeyPair keyPair, final Keystor
100108

101109
private KeyPair getKeyPair(final String clientKey, final String passphrase) throws SessionSecurityException {
102110
try {
103-
return AAAConfigUtils.decodePrivateKey(
111+
return decodePrivateKey(
104112
new StringReader(this.certService
105113
.decrypt(clientKey)
106114
.replace("\\\\n", "\n")),
@@ -112,4 +120,24 @@ private KeyPair getKeyPair(final String clientKey, final String passphrase) thro
112120
throw new RuntimeException(e);
113121
}
114122
}
123+
124+
public static KeyPair decodePrivateKey(final Reader reader, final String passphrase) throws IOException {
125+
try (PEMParser keyReader = new PEMParser(reader)) {
126+
final Provider bcprov;
127+
final var prov = java.security.Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
128+
bcprov = prov != null ? prov : new BouncyCastleProvider();
129+
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
130+
PEMDecryptorProvider decryptionProv = new JcePEMDecryptorProviderBuilder().setProvider(bcprov)
131+
.build(passphrase.toCharArray());
132+
133+
Object privateKey = keyReader.readObject();
134+
KeyPair keyPair;
135+
if (privateKey instanceof PEMEncryptedKeyPair pemPrivateKey) {
136+
keyPair = converter.getKeyPair(pemPrivateKey.decryptKeyPair(decryptionProv));
137+
} else {
138+
keyPair = converter.getKeyPair((PEMKeyPair) privateKey);
139+
}
140+
return keyPair;
141+
}
142+
}
115143
}

lighty-modules/lighty-gnmi/lighty-gnmi-sb/src/test/java/io/lighty/gnmi/southbound/device/KeystoreGnmiSecurityTest.java

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.common.util.concurrent.ListenableFuture;
2121
import io.grpc.ConnectivityState;
2222
import io.grpc.ManagedChannel;
23-
import io.lighty.aaa.encrypt.service.impl.AAAEncryptionServiceImpl;
2423
import io.lighty.gnmi.southbound.device.connection.DeviceConnection;
2524
import io.lighty.gnmi.southbound.device.connection.DeviceConnectionInitializer;
2625
import io.lighty.gnmi.southbound.device.session.security.KeystoreGnmiSecurityProvider;
@@ -36,22 +35,12 @@
3635
import java.nio.charset.Charset;
3736
import java.nio.file.Files;
3837
import java.nio.file.Paths;
39-
import java.security.InvalidAlgorithmParameterException;
40-
import java.security.InvalidKeyException;
41-
import java.security.NoSuchAlgorithmException;
42-
import java.security.spec.InvalidKeySpecException;
43-
import java.security.spec.KeySpec;
44-
import java.util.Base64;
4538
import java.util.Optional;
4639
import java.util.concurrent.ExecutorService;
4740
import java.util.concurrent.Executors;
4841
import java.util.concurrent.TimeUnit;
49-
import javax.crypto.NoSuchPaddingException;
50-
import javax.crypto.SecretKey;
51-
import javax.crypto.SecretKeyFactory;
52-
import javax.crypto.spec.GCMParameterSpec;
53-
import javax.crypto.spec.PBEKeySpec;
54-
import javax.crypto.spec.SecretKeySpec;
42+
import javax.crypto.BadPaddingException;
43+
import javax.crypto.IllegalBlockSizeException;
5544
import javax.xml.bind.DatatypeConverter;
5645
import org.junit.jupiter.api.AfterEach;
5746
import org.junit.jupiter.api.Assertions;
@@ -60,13 +49,15 @@
6049
import org.mockito.ArgumentCaptor;
6150
import org.mockito.MockitoAnnotations;
6251
import org.mockito.Spy;
52+
import org.opendaylight.aaa.encrypt.impl.AAAEncryptionServiceImpl;
6353
import org.opendaylight.mdsal.binding.api.ReadTransaction;
6454
import org.opendaylight.mdsal.binding.api.WriteTransaction;
6555
import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMDataBrokerAdapter;
6656
import org.opendaylight.mdsal.common.api.CommitInfo;
6757
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
6858
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.AaaEncryptServiceConfig;
6959
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.AaaEncryptServiceConfigBuilder;
60+
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.EncryptServiceConfig;
7061
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
7162
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
7263
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
@@ -413,7 +404,7 @@ private static InstanceIdentifier<Keystore> getKeystore2Identifier() {
413404
.build();
414405
}
415406

416-
private static Keystore getKeystore1WithPassResponse() {
407+
private static Keystore getKeystore1WithPassResponse() throws IllegalBlockSizeException, BadPaddingException {
417408
return new KeystoreBuilder()
418409
.setCaCertificate(getResource(CA_CRT))
419410
.setClientCert(getResource(CLIENT_ENCRYPTED_CRT))
@@ -426,7 +417,7 @@ private static Keystore getKeystore1WithPassResponse() {
426417
.build();
427418
}
428419

429-
private static Keystore getKeystore2Response() {
420+
private static Keystore getKeystore2Response() throws IllegalBlockSizeException, BadPaddingException {
430421
return new KeystoreBuilder().setCaCertificate(getResource(CA_CRT)).setClientCert(getResource(CLIENT_CRT))
431422
.setClientKey(DatatypeConverter.printBase64Binary(
432423
(AAA_ENCRYPTION_SERVICE.encrypt((getResource(CLIENT_KEY).getBytes())))))
@@ -447,26 +438,25 @@ private static String getResource(String path) {
447438
}
448439

449440
private static AAAEncryptionServiceImpl createEncryptionServiceWithErrorHandling() {
450-
try {
451-
return createEncryptionService();
452-
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeySpecException
453-
| InvalidAlgorithmParameterException | InvalidKeyException e) {
454-
throw new RuntimeException("Failed to create encryption service", e);
455-
}
441+
return createEncryptionService();
456442
}
457443

458-
private static AAAEncryptionServiceImpl createEncryptionService() throws NoSuchPaddingException,
459-
NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {
460-
final AaaEncryptServiceConfig encrySrvConfig = getDefaultAaaEncryptServiceConfig();
461-
final byte[] encryptionKeySalt = Base64.getDecoder().decode(encrySrvConfig.getEncryptSalt());
462-
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encrySrvConfig.getEncryptMethod());
463-
final KeySpec keySpec = new PBEKeySpec(encrySrvConfig.getEncryptKey().toCharArray(), encryptionKeySalt,
464-
encrySrvConfig.getEncryptIterationCount(), encrySrvConfig.getEncryptKeyLength());
465-
final SecretKey key = new SecretKeySpec(keyFactory.generateSecret(keySpec).getEncoded(),
466-
encrySrvConfig.getEncryptType());
467-
final GCMParameterSpec ivParameterSpec = new GCMParameterSpec(encrySrvConfig.getAuthTagLength(),
468-
encryptionKeySalt);
469-
return new AAAEncryptionServiceImpl(ivParameterSpec, encrySrvConfig.getCipherTransforms(), key);
444+
private static AAAEncryptionServiceImpl createEncryptionService() {
445+
// Build configuration from your test constants
446+
AaaEncryptServiceConfig config = new AaaEncryptServiceConfigBuilder()
447+
.setEncryptKey("V1S1ED4OMeEh")
448+
.setPasswordLength(12)
449+
.setEncryptSalt("TdtWeHbch/7xP52/rp3Usw==")
450+
.setEncryptMethod("PBKDF2WithHmacSHA1")
451+
.setEncryptType("AES")
452+
.setEncryptIterationCount(32768)
453+
.setEncryptKeyLength(128)
454+
.setAuthTagLength(128)
455+
.setCipherTransforms("AES/GCM/NoPadding")
456+
.build();
457+
458+
// The ODL impl expects EncryptServiceConfig, so cast is fine
459+
return new AAAEncryptionServiceImpl((EncryptServiceConfig) config);
470460
}
471461

472462
private static AaaEncryptServiceConfig getDefaultAaaEncryptServiceConfig() {

lighty-modules/lighty-gnmi/lighty-gnmi-sb/src/test/java/io/lighty/gnmi/southbound/lightymodule/GnmiSouthBoundModuleTest.java

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,21 @@
99

1010
import static org.mockito.Mockito.when;
1111

12-
import io.lighty.aaa.encrypt.service.impl.AAAEncryptionServiceImpl;
1312
import io.lighty.core.controller.api.LightyController;
1413
import io.lighty.core.controller.impl.LightyControllerBuilder;
1514
import io.lighty.core.controller.impl.util.ControllerConfigUtils;
1615
import io.lighty.gnmi.southbound.lightymodule.config.GnmiConfiguration;
1716
import io.lighty.gnmi.southbound.lightymodule.util.GnmiConfigUtils;
18-
import java.security.NoSuchAlgorithmException;
19-
import java.security.spec.InvalidKeySpecException;
20-
import java.security.spec.KeySpec;
21-
import java.util.Base64;
2217
import java.util.List;
23-
import java.util.concurrent.Executors;
2418
import java.util.concurrent.TimeUnit;
25-
import javax.crypto.SecretKey;
26-
import javax.crypto.SecretKeyFactory;
27-
import javax.crypto.spec.GCMParameterSpec;
28-
import javax.crypto.spec.PBEKeySpec;
29-
import javax.crypto.spec.SecretKeySpec;
3019
import org.junit.jupiter.api.Assertions;
3120
import org.junit.jupiter.api.Test;
3221
import org.mockito.Mockito;
22+
import org.opendaylight.aaa.encrypt.impl.AAAEncryptionServiceImpl;
3323
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.AaaEncryptServiceConfig;
3424
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.AaaEncryptServiceConfigBuilder;
25+
import org.opendaylight.yang.gen.v1.config.aaa.authn.encrypt.service.config.rev240202.EncryptServiceConfig;
26+
3527

3628
public class GnmiSouthBoundModuleTest {
3729

@@ -72,27 +64,24 @@ public void gnmiModuleStartFailedTest() throws Exception {
7264
Assertions.assertTrue(services.shutdown(MODULE_TIMEOUT, MODULE_TIME_UNIT));
7365
}
7466

75-
private static AAAEncryptionServiceImpl createEncryptionService()
76-
throws NoSuchAlgorithmException, InvalidKeySpecException {
77-
final AaaEncryptServiceConfig encrySrvConfig = getDefaultAaaEncryptServiceConfig();
78-
final byte[] encryptionKeySalt = Base64.getDecoder().decode(encrySrvConfig.getEncryptSalt());
79-
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encrySrvConfig.getEncryptMethod());
80-
final KeySpec keySpec = new PBEKeySpec(encrySrvConfig.getEncryptKey().toCharArray(), encryptionKeySalt,
81-
encrySrvConfig.getEncryptIterationCount(), encrySrvConfig.getEncryptKeyLength());
82-
final SecretKey key
83-
= new SecretKeySpec(keyFactory.generateSecret(keySpec).getEncoded(), encrySrvConfig.getEncryptType());
84-
final GCMParameterSpec ivParameterSpec = new GCMParameterSpec(encrySrvConfig.getAuthTagLength(),
85-
encryptionKeySalt);
86-
return new AAAEncryptionServiceImpl(ivParameterSpec, encrySrvConfig.getCipherTransforms(), key);
87-
}
67+
/**
68+
* Creates the official ODL AAAEncryptionServiceImpl with a test configuration.
69+
*/
70+
private static AAAEncryptionServiceImpl createEncryptionService() {
71+
final AaaEncryptServiceConfig config = new AaaEncryptServiceConfigBuilder()
72+
.setEncryptKey("V1S1ED4OMeEh")
73+
.setPasswordLength(12)
74+
.setEncryptSalt("TdtWeHbch/7xP52/rp3Usw==")
75+
.setEncryptMethod("PBKDF2WithHmacSHA1")
76+
.setEncryptType("AES")
77+
.setEncryptIterationCount(32768)
78+
.setEncryptKeyLength(128)
79+
.setAuthTagLength(128)
80+
.setCipherTransforms("AES/GCM/NoPadding")
81+
.build();
8882

89-
private static AaaEncryptServiceConfig getDefaultAaaEncryptServiceConfig() {
90-
return new AaaEncryptServiceConfigBuilder().setEncryptKey("V1S1ED4OMeEh")
91-
.setPasswordLength(12).setEncryptSalt("TdtWeHbch/7xP52/rp3Usw==")
92-
.setEncryptMethod("PBKDF2WithHmacSHA1").setEncryptType("AES")
93-
.setEncryptIterationCount(32768).setEncryptKeyLength(128)
94-
.setAuthTagLength(128)
95-
.setCipherTransforms("AES/GCM/NoPadding").build();
83+
// This constructor internally handles key derivation, IV setup, etc.
84+
return new AAAEncryptionServiceImpl((EncryptServiceConfig) config);
9685
}
9786
}
9887

lighty-modules/lighty-gnmi/lighty-gnmi-test/src/test/java/io/lighty/modules/gnmi/test/utils/TestUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
package io.lighty.modules.gnmi.test.utils;
1010

1111
import com.google.common.io.CharStreams;
12-
import io.lighty.aaa.util.AAAConfigUtils;
12+
import io.lighty.gnmi.southbound.device.session.security.KeystoreGnmiSecurityProvider;
1313
import io.lighty.gnmi.southbound.device.session.security.SessionSecurityException;
1414
import io.lighty.modules.gnmi.connector.configuration.SecurityFactory;
1515
import io.lighty.modules.gnmi.connector.gnmi.session.impl.GnmiSessionFactoryImpl;
@@ -51,7 +51,7 @@ public static SessionManager createSessionManagerWithCerts() throws IOException,
5151

5252
private static KeyPair getKeyPair(final String clientKey) throws SessionSecurityException {
5353
try {
54-
return AAAConfigUtils.decodePrivateKey(new StringReader(clientKey), PASSPHRASE);
54+
return KeystoreGnmiSecurityProvider.decodePrivateKey(new StringReader(clientKey), PASSPHRASE);
5555
} catch (IOException e) {
5656
throw new SessionSecurityException("Error while creating KeyPair from private key and passphrase", e);
5757
}

0 commit comments

Comments
 (0)