Commit 934020d1842db89a6f9d3be0b3e886d094008520

Authored by Igor Kulikov
2 parents 38e3dcc9 690c97dd

Fix conflicts

... ... @@ -30,8 +30,12 @@ import java.math.BigInteger;
30 30 import java.security.AlgorithmParameters;
31 31 import java.security.GeneralSecurityException;
32 32 import java.security.KeyFactory;
  33 +import java.security.KeyStore;
33 34 import java.security.KeyStoreException;
  35 +import java.security.NoSuchAlgorithmException;
  36 +import java.security.PrivateKey;
34 37 import java.security.PublicKey;
  38 +import java.security.UnrecoverableKeyException;
35 39 import java.security.cert.CertificateEncodingException;
36 40 import java.security.cert.X509Certificate;
37 41 import java.security.spec.ECGenParameterSpec;
... ... @@ -62,49 +66,23 @@ public class LwM2MServerSecurityInfoRepository {
62 66 bsServ.setPort(serverConfig.getPort());
63 67 bsServ.setSecurityHost(serverConfig.getSecureHost());
64 68 bsServ.setSecurityPort(serverConfig.getSecurePort());
65   - bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));
  69 + bsServ.setServerPublicKey(getPublicKey(serverConfig));
66 70 return bsServ;
67 71 }
68 72
69   - private String getPublicKey(String alias, String publicServerX, String publicServerY) {
70   - String publicKey = getServerPublicKeyX509(alias);
71   - return publicKey != null ? publicKey : getRPKPublicKey(publicServerX, publicServerY);
72   - }
73   -
74   - private String getServerPublicKeyX509(String alias) {
75   - try {
76   - X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(alias);
77   - return Hex.encodeHexString(serverCertificate.getEncoded());
78   - } catch (CertificateEncodingException | KeyStoreException e) {
79   - e.printStackTrace();
80   - }
81   - return null;
82   - }
83   -
84   - private String getRPKPublicKey(String publicServerX, String publicServerY) {
  73 + private String getPublicKey(LwM2MSecureServerConfig config) {
85 74 try {
86   - /** Get Elliptic Curve Parameter spec for secp256r1 */
87   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
88   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
89   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
90   - if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) {
91   - /** Get point values */
92   - byte[] publicX = Hex.decodeHex(publicServerX.toCharArray());
93   - byte[] publicY = Hex.decodeHex(publicServerY.toCharArray());
94   - /** Create key specs */
95   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
96   - parameterSpec);
97   - /** Get keys */
98   - PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
99   - if (publicKey != null && publicKey.getEncoded().length > 0) {
100   - return Hex.encodeHexString(publicKey.getEncoded());
101   - }
  75 + KeyStore keyStore = serverConfig.getKeyStoreValue();
  76 + if (keyStore != null) {
  77 + X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias());
  78 + return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded());
102 79 }
103   - } catch (GeneralSecurityException | IllegalArgumentException e) {
104   - log.error("[{}] Failed generate Server RPK for profile", e.getMessage());
105   - throw new RuntimeException(e);
  80 + } catch (Exception e) {
  81 + log.trace("Failed to fetch public key from key store!", e);
  82 +
106 83 }
107   - return null;
  84 + return "";
108 85 }
  86 +
109 87 }
110 88
... ...
... ... @@ -647,48 +647,40 @@ transport:
647 647 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
648 648 bind_port: "${LWM2M_BIND_PORT:5685}"
649 649 security:
650   - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
651   - bind_port: "${LWM2M_BIND_PORT_SECURITY:5686}"
652   - # Only for RPK: Public & Private Key. If the keystore file is missing or not working
653   - public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}"
654   - public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
655   - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
  650 + bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
  651 + bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
656 652 # Only Certificate_x509:
657   - alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}"
  653 + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
  654 + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
658 655 skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
659 656 bootstrap:
660 657 enable: "${LWM2M_ENABLED_BS:true}"
661 658 id: "${LWM2M_SERVER_ID_BS:111}"
662   - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
663   - bind_port: "${LWM2M_BIND_PORT_BS:5687}"
  659 + bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}"
  660 + bind_port: "${LWM2M_BS_BIND_PORT:5687}"
664 661 security:
665   - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY_BS:0.0.0.0}"
666   - bind_port: "${LWM2M_BIND_PORT_SECURITY_BS:5688}"
667   - # Only for RPK: Public & Private Key. If the keystore file is missing or not working
668   - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}"
669   - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
670   - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
  662 + bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
  663 + bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
671 664 # Only Certificate_x509:
672   - alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}"
  665 + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
  666 + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
673 667 security:
674 668 # Certificate_x509:
675 669 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
676 670 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
677 671 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
678 672 # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
679   - key_store: "${LWM2M_KEY_STORE:lwm2mserver.jks}"
680   - key_store_password: "${LWM2M_KEY_STORE_PASSWORD:server_ks_password}"
681   - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}"
682   - enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}"
  673 + key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
  674 + key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
  675 + root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
  676 + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
  677 + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
683 678 timeout: "${LWM2M_TIMEOUT:120000}"
684   - recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
685   - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
686 679 uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}"
687 680 downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}"
688 681 ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}"
689   - registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
690 682 clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
691   - log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
  683 + log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}"
692 684 # Use redis for Security and Registration stores
693 685 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
694 686 snmp:
... ...
1 1 transport.lwm2m.security.key_store=lwm2m/credentials/serverKeyStore.jks
2 2 transport.lwm2m.security.key_store_password=server
3 3 edges.enabled=true
4   -transport.lwm2m.bootstrap.security.alias=server
\ No newline at end of file
  4 +transport.lwm2m.server.security.key_alias=server
  5 +transport.lwm2m.server.security.key_password=server
  6 +transport.lwm2m.bootstrap.security.key_alias=server
  7 +transport.lwm2m.bootstrap.security.key_password=server
\ No newline at end of file
... ...
... ... @@ -19,57 +19,33 @@ import lombok.RequiredArgsConstructor;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.eclipse.californium.elements.util.SslContextUtil;
21 21 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
22   -import org.eclipse.leshan.core.util.Hex;
23 22 import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
24 23 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
25 24 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder;
26 25 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
27 26 import org.springframework.stereotype.Component;
28   -import org.thingsboard.server.common.data.StringUtils;
29 27 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
30 28 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
31 29 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager;
32 30 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
33 31 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
34   -import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
  32 +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService;
35 33
36 34 import javax.annotation.PostConstruct;
37 35 import javax.annotation.PreDestroy;
38   -import java.math.BigInteger;
39   -import java.security.AlgorithmParameters;
40   -import java.security.KeyFactory;
41 36 import java.security.KeyStore;
42 37 import java.security.KeyStoreException;
43   -import java.security.NoSuchAlgorithmException;
44 38 import java.security.PrivateKey;
45 39 import java.security.PublicKey;
46   -import java.security.cert.CertificateEncodingException;
47 40 import java.security.cert.X509Certificate;
48   -import java.security.interfaces.ECPublicKey;
49   -import java.security.spec.ECGenParameterSpec;
50   -import java.security.spec.ECParameterSpec;
51   -import java.security.spec.ECPoint;
52   -import java.security.spec.ECPublicKeySpec;
53   -import java.security.spec.InvalidKeySpecException;
54   -import java.security.spec.InvalidParameterSpecException;
55   -import java.security.spec.KeySpec;
56   -import java.security.spec.PKCS8EncodedKeySpec;
57   -import java.util.Arrays;
58 41
59   -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
60   -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
61   -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
62   -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8;
63 42 import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig;
64 43
65 44 @Slf4j
66 45 @Component
67 46 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')")
68 47 @RequiredArgsConstructor
69   -//TODO: @ybondarenko please refactor this to be similar to DefaultLwM2mTransportService
70 48 public class LwM2MTransportBootstrapService {
71   - private PublicKey publicKey;
72   - private PrivateKey privateKey;
73 49 private boolean pskMode = false;
74 50
75 51 private final LwM2MTransportServerConfig serverConfig;
... ... @@ -81,9 +57,6 @@ public class LwM2MTransportBootstrapService {
81 57
82 58 @PostConstruct
83 59 public void init() {
84   - if (serverConfig.getEnableGenNewKeyPskRpk()) {
85   - new LWM2MGenerationPSkRPkECC();
86   - }
87 60 log.info("Starting LwM2M transport bootstrap server...");
88 61 this.server = getLhBootstrapServer();
89 62 this.server.start();
... ... @@ -102,44 +75,34 @@ public class LwM2MTransportBootstrapService {
102 75 builder.setLocalAddress(bootstrapConfig.getHost(), bootstrapConfig.getPort());
103 76 builder.setLocalSecureAddress(bootstrapConfig.getSecureHost(), bootstrapConfig.getSecurePort());
104 77
105   - /** Create CoAP Config */
  78 + /* Create CoAP Config */
106 79 builder.setCoapConfig(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig));
107 80
108   - /** Define model provider (Create Models )*/
  81 + /* Define model provider (Create Models )*/
109 82
110   - /** Create credentials */
  83 + /* Create credentials */
111 84 this.setServerWithCredentials(builder);
112 85
113 86 // /** Set securityStore with new ConfigStore */
114 87 // builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore);
115 88
116   - /** SecurityStore */
  89 + /* SecurityStore */
117 90 builder.setSecurityStore(lwM2MBootstrapSecurityStore);
118 91
119 92
120   - /** Create and Set DTLS Config */
  93 + /* Create and Set DTLS Config */
121 94 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
122 95 dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups());
123 96 dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers());
124   - if (this.pskMode) {
125   - dtlsConfig.setSupportedCipherSuites(
126   - TLS_PSK_WITH_AES_128_CCM_8,
127   - TLS_PSK_WITH_AES_128_CBC_SHA256);
128   - } else {
129   - dtlsConfig.setSupportedCipherSuites(
130   - TLS_PSK_WITH_AES_128_CCM_8,
131   - TLS_PSK_WITH_AES_128_CBC_SHA256,
132   - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
133   - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
134   - }
  97 + dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES);
135 98
136   - /** Set DTLS Config */
  99 + /* Set DTLS Config */
137 100 builder.setDtlsConfig(dtlsConfig);
138 101
139 102 BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore);
140 103 builder.setSessionManager(sessionManager);
141 104
142   - /** Create BootstrapServer */
  105 + /* Create BootstrapServer */
143 106 return builder.build();
144 107 }
145 108
... ... @@ -154,19 +117,15 @@ public class LwM2MTransportBootstrapService {
154 117 trustedCertificates[0] = rootCAX509Cert;
155 118 builder.setTrustedCertificates(trustedCertificates);
156 119 } else {
157   - /** by default trust all */
  120 + /* by default trust all */
158 121 builder.setTrustedCertificates(new X509Certificate[0]);
159 122 }
160 123 }
161   - } else if (this.setServerRPK(builder)) {
162   - this.infoPramsUri("RPK");
163   - this.infoParamsBootstrapServerKey(this.publicKey, this.privateKey);
164 124 } else {
165   - /** by default trust all */
  125 + /* by default trust all */
166 126 builder.setTrustedCertificates(new X509Certificate[0]);
167 127 log.info("Unable to load X509 files for BootStrapServer");
168 128 this.pskMode = true;
169   - this.infoPramsUri("PSK");
170 129 }
171 130 } catch (KeyStoreException ex) {
172 131 log.error("[{}] Unable to load X509 files server", ex.getMessage());
... ... @@ -174,20 +133,15 @@ public class LwM2MTransportBootstrapService {
174 133 }
175 134
176 135 private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) {
177   - /**
178   - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE
179   - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
180   - */
181 136 try {
182 137 X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(serverConfig.getKeyStoreValue().getCertificateChain(this.bootstrapConfig.getCertificateAlias()));
183 138 X509Certificate serverCertificate = certificateChain[0];
184   - PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getKeyStorePassword() == null ? null : serverConfig.getKeyStorePassword().toCharArray());
  139 + PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getCertificatePassword() == null ? null : serverConfig.getCertificatePassword().toCharArray());
185 140 PublicKey publicKey = serverCertificate.getPublicKey();
186 141 if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
187 142 builder.setPublicKey(serverCertificate.getPublicKey());
188 143 builder.setPrivateKey(privateKey);
189 144 builder.setCertificateChain(certificateChain);
190   - this.infoParamsServerX509(serverCertificate, publicKey, privateKey);
191 145 return true;
192 146 } else {
193 147 return false;
... ... @@ -198,105 +152,4 @@ public class LwM2MTransportBootstrapService {
198 152 }
199 153 }
200 154
201   - private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) {
202   - try {
203   - this.infoPramsUri("X509");
204   - log.info("\n- X509 Certificate (Hex): [{}]",
205   - Hex.encodeHexString(certificate.getEncoded()));
206   - this.infoParamsBootstrapServerKey(publicKey, privateKey);
207   - } catch (CertificateEncodingException e) {
208   - log.error("", e);
209   - }
210   - }
211   -
212   - private void infoPramsUri(String mode) {
213   - log.info("Bootstrap Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]",
214   - mode,
215   - this.bootstrapConfig.getHost(),
216   - this.bootstrapConfig.getPort(),
217   - this.bootstrapConfig.getSecureHost(),
218   - this.bootstrapConfig.getSecurePort());
219   - }
220   -
221   -
222   - private boolean setServerRPK(LeshanBootstrapServerBuilder builder) {
223   - try {
224   - this.generateKeyForBootstrapRPK();
225   - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
226   - this.privateKey != null && this.privateKey.getEncoded().length > 0) {
227   - builder.setPublicKey(this.publicKey);
228   -// builder.setCertificateChain(new X509Certificate[] { serverCertificate });
229   - /// Trust all certificates.
230   - builder.setTrustedCertificates(new X509Certificate[0]);
231   - builder.setPrivateKey(this.privateKey);
232   - return true;
233   - }
234   - } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) {
235   - log.error("Fail create Bootstrap Server with RPK", e);
236   - }
237   - return false;
238   - }
239   -
240   -
241   - /**
242   - * From yml: bootstrap
243   - * public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}"
244   - * public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}"
245   - * private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}"
246   - */
247   - private void generateKeyForBootstrapRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
248   - /** Get Elliptic Curve Parameter spec for secp256r1 */
249   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
250   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
251   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
252   - LwM2MTransportBootstrapConfig serverConfig = this.bootstrapConfig;
253   - if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) {
254   - /** Get point values */
255   - byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray());
256   - byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray());
257   - /** Create key specs */
258   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
259   - parameterSpec);
260   - /** Get public key */
261   - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
262   - }
263   - String privateEncodedKey = serverConfig.getPrivateEncoded();
264   - if (StringUtils.isNotEmpty(privateEncodedKey)) {
265   - /** Get private key */
266   - byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray());
267   - try {
268   - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS));
269   - } catch (InvalidKeySpecException ignore2) {
270   - log.error("Invalid Bootstrap Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey);
271   - }
272   - }
273   - }
274   -
275   - private void infoParamsBootstrapServerKey(PublicKey publicKey, PrivateKey privateKey) {
276   - /** Get x coordinate */
277   - byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray();
278   - if (x[0] == 0)
279   - x = Arrays.copyOfRange(x, 1, x.length);
280   -
281   - /** Get Y coordinate */
282   - byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray();
283   - if (y[0] == 0)
284   - y = Arrays.copyOfRange(y, 1, y.length);
285   -
286   - /** Get Curves params */
287   - String params = ((ECPublicKey) publicKey).getParams().toString();
288   - String privHex = Hex.encodeHexString(privateKey.getEncoded());
289   - log.info("\n- Public Key (Hex): [{}] \n" +
290   - "- Private Key (Hex): [{}], \n" +
291   - "public_x: \"${LWM2M_SERVER_PUBLIC_X_BS:{}}\" \n" +
292   - "public_y: \"${LWM2M_SERVER_PUBLIC_Y_BS:{}}\" \n" +
293   - "private_encoded: \"${LWM2M_SERVER_PRIVATE_ENCODED_BS:{}}\" \n" +
294   - "- Elliptic Curve parameters : [{}]",
295   - Hex.encodeHexString(publicKey.getEncoded()),
296   - privHex,
297   - Hex.encodeHexString(x),
298   - Hex.encodeHexString(y),
299   - privHex,
300   - params);
301   - }
302 155 }
... ...
... ... @@ -27,12 +27,8 @@ public interface LwM2MSecureServerConfig {
27 27
28 28 Integer getSecurePort();
29 29
30   - String getPublicX();
31   -
32   - String getPublicY();
33   -
34   - String getPrivateEncoded();
35   -
36 30 String getCertificateAlias();
37 31
  32 + String getCertificatePassword();
  33 +
38 34 }
... ...
... ... @@ -47,19 +47,11 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig {
47 47 private Integer securePort;
48 48
49 49 @Getter
50   - @Value("${transport.lwm2m.bootstrap.security.public_x:}")
51   - private String publicX;
52   -
53   - @Getter
54   - @Value("${transport.lwm2m.bootstrap.security.public_y:}")
55   - private String publicY;
56   -
57   - @Getter
58   - @Value("${transport.lwm2m.bootstrap.security.private_encoded:}")
59   - private String privateEncoded;
  50 + @Value("${transport.lwm2m.bootstrap.security.key_alias:}")
  51 + private String certificateAlias;
60 52
61 53 @Getter
62   - @Value("${transport.lwm2m.bootstrap.security.alias:}")
63   - private String certificateAlias;
  54 + @Value("${transport.lwm2m.bootstrap.security.key_password:}")
  55 + private String certificatePassword;
64 56
65 57 }
... ...
... ... @@ -53,11 +53,11 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
53 53 private long sessionReportTimeout;
54 54
55 55 @Getter
56   - @Value("${transport.lwm2m.recommended_ciphers:}")
  56 + @Value("${transport.lwm2m.security.recommended_ciphers:}")
57 57 private boolean recommendedCiphers;
58 58
59 59 @Getter
60   - @Value("${transport.lwm2m.recommended_supported_groups:}")
  60 + @Value("${transport.lwm2m.security.recommended_supported_groups:}")
61 61 private boolean recommendedSupportedGroups;
62 62
63 63 @Getter
... ... @@ -97,10 +97,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
97 97 private String rootCertificateAlias;
98 98
99 99 @Getter
100   - @Value("${transport.lwm2m.security.enable_gen_new_key_psk_rpk:}")
101   - private Boolean enableGenNewKeyPskRpk;
102   -
103   - @Getter
104 100 @Value("${transport.lwm2m.server.id:}")
105 101 private Integer id;
106 102
... ... @@ -121,20 +117,12 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
121 117 private Integer securePort;
122 118
123 119 @Getter
124   - @Value("${transport.lwm2m.server.security.public_x:}")
125   - private String publicX;
126   -
127   - @Getter
128   - @Value("${transport.lwm2m.server.security.public_y:}")
129   - private String publicY;
130   -
131   - @Getter
132   - @Value("${transport.lwm2m.server.security.private_encoded:}")
133   - private String privateEncoded;
  120 + @Value("${transport.lwm2m.server.security.key_alias:}")
  121 + private String certificateAlias;
134 122
135 123 @Getter
136   - @Value("${transport.lwm2m.server.security.alias:}")
137   - private String certificateAlias;
  124 + @Value("${transport.lwm2m.server.security.key_password:}")
  125 + private String certificatePassword;
138 126
139 127 @Getter
140 128 @Value("${transport.lwm2m.log_max_length:}")
... ...
1   -/**
2   - * Copyright © 2016-2021 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.core.util.Hex;
20   -
21   -import java.security.InvalidAlgorithmParameterException;
22   -import java.security.KeyPair;
23   -import java.security.KeyPairGenerator;
24   -import java.security.NoSuchAlgorithmException;
25   -import java.security.NoSuchProviderException;
26   -import java.security.PrivateKey;
27   -import java.security.PublicKey;
28   -import java.security.SecureRandom;
29   -import java.security.interfaces.ECPublicKey;
30   -import java.security.spec.ECGenParameterSpec;
31   -import java.util.Arrays;
32   -
33   -@Slf4j
34   -public class LWM2MGenerationPSkRPkECC {
35   -
36   - public LWM2MGenerationPSkRPkECC() {
37   - generationPSkKey();
38   - generationRPKECCKey();
39   - }
40   -
41   - private void generationPSkKey() {
42   - /* PSK */
43   - int lenPSkKey = 32;
44   - /* Start PSK
45   - Clients and Servers MUST support PSK keys of up to 64 bytes in length, as required by [RFC7925]
46   - SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in [RFC4086]
47   - */
48   - SecureRandom randomPSK = new SecureRandom();
49   - byte[] bytesPSK = new byte[lenPSkKey];
50   - randomPSK.nextBytes(bytesPSK);
51   - log.info("\nCreating new PSK: \n for the next start PSK -> security key: [{}]", Hex.encodeHexString(bytesPSK));
52   - }
53   -
54   - private void generationRPKECCKey() {
55   - /* RPK */
56   - String algorithm = "EC";
57   - String provider = "SunEC";
58   - String nameParameterSpec = "secp256r1";
59   -
60   - /* Start RPK
61   - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)]
62   - */
63   - KeyPairGenerator kpg = null;
64   - try {
65   - kpg = KeyPairGenerator.getInstance(algorithm, provider);
66   - } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
67   - log.error("", e);
68   - }
69   - ECGenParameterSpec ecsp = new ECGenParameterSpec(nameParameterSpec);
70   - try {
71   - kpg.initialize(ecsp);
72   - } catch (InvalidAlgorithmParameterException e) {
73   - log.error("", e);
74   - }
75   -
76   - KeyPair kp = kpg.genKeyPair();
77   - PrivateKey privKey = kp.getPrivate();
78   - PublicKey pubKey = kp.getPublic();
79   -
80   - if (pubKey instanceof ECPublicKey) {
81   - ECPublicKey ecPublicKey = (ECPublicKey) pubKey;
82   - /* Get x coordinate */
83   - byte[] x = ecPublicKey.getW().getAffineX().toByteArray();
84   - if (x[0] == 0)
85   - x = Arrays.copyOfRange(x, 1, x.length);
86   -
87   - /* Get Y coordinate */
88   - byte[] y = ecPublicKey.getW().getAffineY().toByteArray();
89   - if (y[0] == 0)
90   - y = Arrays.copyOfRange(y, 1, y.length);
91   -
92   - /* Get Curves params */
93   - String privHex = Hex.encodeHexString(privKey.getEncoded());
94   - log.info("\nCreating new RPK for the next start... \n" +
95   - " Public Key (Hex): [{}]\n" +
96   - " Private Key (Hex): [{}]" +
97   - " public_x : [{}] \n" +
98   - " public_y : [{}] \n" +
99   - " private_encode : [{}] \n" +
100   - " Elliptic Curve parameters : [{}] \n",
101   - Hex.encodeHexString(pubKey.getEncoded()),
102   - privHex,
103   - Hex.encodeHexString(x),
104   - Hex.encodeHexString(y),
105   - privHex,
106   - ecPublicKey.getParams().toString());
107   - }
108   - }
109   -}
110   -
... ... @@ -22,17 +22,14 @@ import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
22 22 import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
23 23 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder;
24 24 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder;
25   -import org.eclipse.leshan.core.util.Hex;
26 25 import org.eclipse.leshan.server.californium.LeshanServer;
27 26 import org.eclipse.leshan.server.californium.LeshanServerBuilder;
28 27 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
29 28 import org.eclipse.leshan.server.model.LwM2mModelProvider;
30 29 import org.springframework.stereotype.Component;
31 30 import org.thingsboard.server.cache.ota.OtaPackageDataCache;
32   -import org.thingsboard.server.common.data.StringUtils;
33 31 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
34 32 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
35   -import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
36 33 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
37 34 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
38 35 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
... ... @@ -42,25 +39,9 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
42 39
43 40 import javax.annotation.PostConstruct;
44 41 import javax.annotation.PreDestroy;
45   -import java.math.BigInteger;
46   -import java.security.AlgorithmParameters;
47   -import java.security.KeyFactory;
48   -import java.security.NoSuchAlgorithmException;
49 42 import java.security.PrivateKey;
50 43 import java.security.PublicKey;
51   -import java.security.cert.Certificate;
52   -import java.security.cert.CertificateEncodingException;
53 44 import java.security.cert.X509Certificate;
54   -import java.security.interfaces.ECPublicKey;
55   -import java.security.spec.ECGenParameterSpec;
56   -import java.security.spec.ECParameterSpec;
57   -import java.security.spec.ECPoint;
58   -import java.security.spec.ECPublicKeySpec;
59   -import java.security.spec.InvalidKeySpecException;
60   -import java.security.spec.InvalidParameterSpecException;
61   -import java.security.spec.KeySpec;
62   -import java.security.spec.PKCS8EncodedKeySpec;
63   -import java.util.Arrays;
64 45
65 46 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
66 47 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
... ... @@ -77,8 +58,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
77 58
78 59 public static final CipherSuite[] RPK_OR_X509_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256};
79 60 public static final CipherSuite[] PSK_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256};
80   - private PublicKey publicKey;
81   - private PrivateKey privateKey;
82 61
83 62 private final LwM2mTransportContext context;
84 63 private final LwM2MTransportServerConfig config;
... ... @@ -95,18 +74,14 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
95 74
96 75 @PostConstruct
97 76 public void init() {
98   - if (config.getEnableGenNewKeyPskRpk()) {
99   - new LWM2MGenerationPSkRPkECC();
100   - }
101 77 this.server = getLhServer();
102   - /**
  78 + /*
103 79 * Add a resource to the server.
104 80 * CoapResource ->
105 81 * path = FW_PACKAGE or SW_PACKAGE
106 82 * nameFile = "BC68JAR01A09_TO_BC68JAR01A10.bin"
107 83 * "coap://host:port/{path}/{token}/{nameFile}"
108 84 */
109   -
110 85 LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE);
111 86 this.server.coap().getServer().add(otaCoapResource);
112 87 this.startLhServer();
... ... @@ -172,16 +147,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
172 147 dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
173 148 builder.setAuthorizer(authorizer);
174 149 dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
175   - } else if (this.setServerRPK(builder)) {
176   - this.infoPramsUri("RPK");
177   - this.infoParamsServerKey(this.publicKey, this.privateKey);
178   - dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
179 150 } else {
180 151 /* by default trust all */
181 152 builder.setTrustedCertificates(new X509Certificate[0]);
182 153 log.info("Unable to load X509 files for LWM2MServer");
183 154 dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES);
184   - this.infoPramsUri("PSK");
185 155 }
186 156 }
187 157
... ... @@ -189,13 +159,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
189 159 try {
190 160 X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(config.getKeyStoreValue().getCertificateChain(config.getCertificateAlias()));
191 161 X509Certificate serverCertificate = certificateChain[0];
192   - PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getKeyStorePassword() == null ? null : config.getKeyStorePassword().toCharArray());
  162 + PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getCertificatePassword() == null ? null : config.getCertificatePassword().toCharArray());
193 163 PublicKey publicKey = serverCertificate.getPublicKey();
194 164 if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
195 165 builder.setPublicKey(serverCertificate.getPublicKey());
196 166 builder.setPrivateKey(privateKey);
197 167 builder.setCertificateChain(certificateChain);
198   - this.infoParamsServerX509(serverCertificate, publicKey, privateKey);
199 168 return true;
200 169 } else {
201 170 return false;
... ... @@ -206,93 +175,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
206 175 }
207 176 }
208 177
209   - private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) {
210   - try {
211   - infoPramsUri("X509");
212   - log.info("\n- X509 Certificate (Hex): [{}]",
213   - Hex.encodeHexString(certificate.getEncoded()));
214   - this.infoParamsServerKey(publicKey, privateKey);
215   - } catch (CertificateEncodingException e) {
216   - log.error("", e);
217   - }
218   - }
219   -
220   - private void infoPramsUri(String mode) {
221   - LwM2MTransportServerConfig lwM2MTransportServerConfig = config;
222   - log.info("Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]", mode,
223   - lwM2MTransportServerConfig.getHost(),
224   - lwM2MTransportServerConfig.getPort(),
225   - lwM2MTransportServerConfig.getSecureHost(),
226   - lwM2MTransportServerConfig.getSecurePort());
227   - }
228   -
229   - private boolean setServerRPK(LeshanServerBuilder builder) {
230   - try {
231   - this.loadOrGenerateRPKKeys();
232   - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
233   - this.privateKey != null && this.privateKey.getEncoded().length > 0) {
234   - builder.setPublicKey(this.publicKey);
235   - builder.setPrivateKey(this.privateKey);
236   - return true;
237   - }
238   - } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) {
239   - log.error("Fail create Server with RPK", e);
240   - }
241   - return false;
242   - }
243   -
244   - private void loadOrGenerateRPKKeys() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
245   - /* Get Elliptic Curve Parameter spec for secp256r1 */
246   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
247   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
248   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
249   - LwM2MTransportServerConfig serverConfig = config;
250   - if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) {
251   - byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray());
252   - byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray());
253   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
254   - parameterSpec);
255   - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
256   - }
257   - String privateEncodedKey = serverConfig.getPrivateEncoded();
258   - if (StringUtils.isNotEmpty(privateEncodedKey)) {
259   - byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray());
260   - try {
261   - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS));
262   - } catch (InvalidKeySpecException ignore2) {
263   - log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey);
264   - }
265   - }
266   - }
267   -
268   - private void infoParamsServerKey(PublicKey publicKey, PrivateKey privateKey) {
269   - /* Get x coordinate */
270   - byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray();
271   - if (x[0] == 0)
272   - x = Arrays.copyOfRange(x, 1, x.length);
273   -
274   - /* Get Y coordinate */
275   - byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray();
276   - if (y[0] == 0)
277   - y = Arrays.copyOfRange(y, 1, y.length);
278   -
279   - /* Get Curves params */
280   - String params = ((ECPublicKey) publicKey).getParams().toString();
281   - String privHex = Hex.encodeHexString(privateKey.getEncoded());
282   - log.info(" \n- Public Key (Hex): [{}] \n" +
283   - "- Private Key (Hex): [{}], \n" +
284   - "public_x: \"${LWM2M_SERVER_PUBLIC_X:{}}\" \n" +
285   - "public_y: \"${LWM2M_SERVER_PUBLIC_Y:{}}\" \n" +
286   - "private_encoded: \"${LWM2M_SERVER_PRIVATE_ENCODED:{}}\" \n" +
287   - "- Elliptic Curve parameters : [{}]",
288   - Hex.encodeHexString(publicKey.getEncoded()),
289   - privHex,
290   - Hex.encodeHexString(x),
291   - Hex.encodeHexString(y),
292   - privHex,
293   - params);
294   - }
295   -
296 178 @Override
297 179 public String getName() {
298 180 return "LWM2M";
... ...
... ... @@ -19,10 +19,12 @@ import com.google.common.util.concurrent.Futures;
19 19 import com.google.common.util.concurrent.ListenableFuture;
20 20 import com.google.common.util.concurrent.MoreExecutors;
21 21 import lombok.extern.slf4j.Slf4j;
  22 +import org.springframework.beans.factory.annotation.Value;
22 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23 24 import org.springframework.cache.Cache;
24 25 import org.springframework.context.annotation.Primary;
25 26 import org.springframework.stereotype.Service;
  27 +import org.springframework.util.StringUtils;
26 28 import org.thingsboard.server.common.data.EntityType;
27 29 import org.thingsboard.server.common.data.id.DeviceProfileId;
28 30 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -34,6 +36,7 @@ import org.thingsboard.server.common.stats.StatsFactory;
34 36 import org.thingsboard.server.dao.cache.CacheExecutorService;
35 37 import org.thingsboard.server.dao.service.Validator;
36 38
  39 +import javax.annotation.PostConstruct;
37 40 import java.util.ArrayList;
38 41 import java.util.Collection;
39 42 import java.util.HashMap;
... ... @@ -43,6 +46,7 @@ import java.util.Map;
43 46 import java.util.Objects;
44 47 import java.util.Optional;
45 48 import java.util.Set;
  49 +import java.util.concurrent.Executor;
46 50 import java.util.stream.Collectors;
47 51
48 52 import static org.thingsboard.server.dao.attributes.AttributeUtils.validate;
... ... @@ -53,12 +57,17 @@ import static org.thingsboard.server.dao.attributes.AttributeUtils.validate;
53 57 @Slf4j
54 58 public class CachedAttributesService implements AttributesService {
55 59 private static final String STATS_NAME = "attributes.cache";
  60 + public static final String LOCAL_CACHE_TYPE = "caffeine";
56 61
57 62 private final AttributesDao attributesDao;
58 63 private final AttributesCacheWrapper cacheWrapper;
  64 + private final CacheExecutorService cacheExecutorService;
59 65 private final DefaultCounter hitCounter;
60 66 private final DefaultCounter missCounter;
61   - private final CacheExecutorService cacheExecutorService;
  67 + private Executor cacheExecutor;
  68 +
  69 + @Value("${cache.type}")
  70 + private String cacheType;
62 71
63 72 public CachedAttributesService(AttributesDao attributesDao,
64 73 AttributesCacheWrapper cacheWrapper,
... ... @@ -72,6 +81,25 @@ public class CachedAttributesService implements AttributesService {
72 81 this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss");
73 82 }
74 83
  84 + @PostConstruct
  85 + public void init() {
  86 + this.cacheExecutor = getExecutor(cacheType, cacheExecutorService);
  87 + }
  88 +
  89 + /**
  90 + * Will return:
  91 + * - for the <b>local</b> cache type (cache.type="coffeine"): directExecutor (run callback immediately in the same thread)
  92 + * - for the <b>remote</b> cache: dedicated thread pool for the cache IO calls to unblock any caller thread
  93 + * */
  94 + Executor getExecutor(String cacheType, CacheExecutorService cacheExecutorService) {
  95 + if (StringUtils.isEmpty(cacheType) || LOCAL_CACHE_TYPE.equals(cacheType)) {
  96 + log.info("Going to use directExecutor for the local cache type {}", cacheType);
  97 + return MoreExecutors.directExecutor();
  98 + }
  99 + log.info("Going to use cacheExecutorService for the remote cache type {}", cacheType);
  100 + return cacheExecutorService;
  101 + }
  102 +
75 103 @Override
76 104 public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey) {
77 105 validate(entityId, scope);
... ... @@ -90,7 +118,7 @@ public class CachedAttributesService implements AttributesService {
90 118 // TODO: think if it's a good idea to store 'empty' attributes
91 119 cacheWrapper.put(attributeCacheKey, foundAttrKvEntry.orElse(null));
92 120 return foundAttrKvEntry;
93   - }, cacheExecutorService);
  121 + }, cacheExecutor);
94 122 }
95 123 }
96 124
... ... @@ -113,7 +141,7 @@ public class CachedAttributesService implements AttributesService {
113 141 notFoundAttributeKeys.removeAll(wrappedCachedAttributes.keySet());
114 142
115 143 ListenableFuture<List<AttributeKvEntry>> result = attributesDao.find(tenantId, entityId, scope, notFoundAttributeKeys);
116   - return Futures.transform(result, foundInDbAttributes -> mergeDbAndCacheAttributes(entityId, scope, cachedAttributes, notFoundAttributeKeys, foundInDbAttributes), cacheExecutorService);
  144 + return Futures.transform(result, foundInDbAttributes -> mergeDbAndCacheAttributes(entityId, scope, cachedAttributes, notFoundAttributeKeys, foundInDbAttributes), cacheExecutor);
117 145
118 146 }
119 147
... ... @@ -171,7 +199,7 @@ public class CachedAttributesService implements AttributesService {
171 199
172 200 // TODO: can do if (attributesCache.get() != null) attributesCache.put() instead, but will be more twice more requests to cache
173 201 List<String> attributeKeys = attributes.stream().map(KvEntry::getKey).collect(Collectors.toList());
174   - future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutorService);
  202 + future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutor);
175 203 return future;
176 204 }
177 205
... ... @@ -179,7 +207,7 @@ public class CachedAttributesService implements AttributesService {
179 207 public ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys) {
180 208 validate(entityId, scope);
181 209 ListenableFuture<List<Void>> future = attributesDao.removeAll(tenantId, entityId, scope, attributeKeys);
182   - future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutorService);
  210 + future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutor);
183 211 return future;
184 212 }
185 213
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.attributes;
  17 +
  18 +import com.google.common.util.concurrent.MoreExecutors;
  19 +import org.junit.Test;
  20 +import org.thingsboard.server.dao.cache.CacheExecutorService;
  21 +
  22 +import static org.hamcrest.CoreMatchers.is;
  23 +import static org.hamcrest.MatcherAssert.assertThat;
  24 +import static org.mockito.ArgumentMatchers.any;
  25 +import static org.mockito.BDDMockito.willCallRealMethod;
  26 +import static org.mockito.Mockito.mock;
  27 +
  28 +public class CachedAttributesServiceTest {
  29 +
  30 + public static final String REDIS = "redis";
  31 +
  32 + @Test
  33 + public void givenLocalCacheTypeName_whenEquals_thenOK() {
  34 + assertThat(CachedAttributesService.LOCAL_CACHE_TYPE, is("caffeine"));
  35 + }
  36 +
  37 + @Test
  38 + public void givenCacheType_whenGetExecutor_thenDirectExecutor() {
  39 + CachedAttributesService cachedAttributesService = mock(CachedAttributesService.class);
  40 + CacheExecutorService cacheExecutorService = mock(CacheExecutorService.class);
  41 + willCallRealMethod().given(cachedAttributesService).getExecutor(any(), any());
  42 +
  43 + assertThat(cachedAttributesService.getExecutor(null, cacheExecutorService), is(MoreExecutors.directExecutor()));
  44 +
  45 + assertThat(cachedAttributesService.getExecutor("", cacheExecutorService), is(MoreExecutors.directExecutor()));
  46 +
  47 + assertThat(cachedAttributesService.getExecutor(CachedAttributesService.LOCAL_CACHE_TYPE, cacheExecutorService), is(MoreExecutors.directExecutor()));
  48 +
  49 + }
  50 +
  51 + @Test
  52 + public void givenCacheType_whenGetExecutor_thenReturnCacheExecutorService() {
  53 + CachedAttributesService cachedAttributesService = mock(CachedAttributesService.class);
  54 + CacheExecutorService cacheExecutorService = mock(CacheExecutorService.class);
  55 + willCallRealMethod().given(cachedAttributesService).getExecutor(any(String.class), any(CacheExecutorService.class));
  56 +
  57 + assertThat(cachedAttributesService.getExecutor(REDIS, cacheExecutorService), is(cacheExecutorService));
  58 +
  59 + assertThat(cachedAttributesService.getExecutor("unknownCacheType", cacheExecutorService), is(cacheExecutorService));
  60 +
  61 + }
  62 +
  63 +}
\ No newline at end of file
... ...
... ... @@ -106,47 +106,40 @@ transport:
106 106 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
107 107 bind_port: "${LWM2M_BIND_PORT:5685}"
108 108 security:
109   - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
110   - bind_port: "${LWM2M_BIND_PORT_SECURITY:5686}"
111   - # Only for RPK: Public & Private Key. If the keystore file is missing or not working
112   - public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}"
113   - public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
114   - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
  109 + bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
  110 + bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
115 111 # Only Certificate_x509:
116   - alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}"
  112 + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
  113 + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
117 114 skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
118 115 bootstrap:
119 116 enable: "${LWM2M_ENABLED_BS:true}"
120 117 id: "${LWM2M_SERVER_ID_BS:111}"
121   - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
122   - bind_port: "${LWM2M_BIND_PORT_BS:5687}"
  118 + bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}"
  119 + bind_port: "${LWM2M_BS_BIND_PORT:5687}"
123 120 security:
124   - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY_BS:0.0.0.0}"
125   - bind_port: "${LWM2M_BIND_PORT_SECURITY_BS:5688}"
126   - # Only for RPK: Public & Private Key. If the keystore file is missing or not working
127   - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}"
128   - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
129   - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
  121 + bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
  122 + bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
130 123 # Only Certificate_x509:
131   - alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}"
  124 + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
  125 + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
132 126 security:
133 127 # Certificate_x509:
134 128 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
135 129 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
136 130 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
137 131 # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
138   - key_store: "${LWM2M_KEY_STORE:lwm2mserver.jks}"
139   - key_store_password: "${LWM2M_KEY_STORE_PASSWORD:server_ks_password}"
140   - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}"
141   - enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}"
  132 + key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
  133 + key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
  134 + root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
  135 + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
  136 + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
142 137 timeout: "${LWM2M_TIMEOUT:120000}"
143   - recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
144   - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
145 138 uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}"
146 139 downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}"
147 140 ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}"
148 141 clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
149   - log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
  142 + log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}"
150 143 # Use redis for Security and Registration stores
151 144 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
152 145
... ...