CoAP DTLS support (#4316)
* dtls init commit * added fixes after review * fix typo * changed translation for DeviceCredentialsType.X509_CERTIFICATE
This commit is contained in:
parent
68a73caada
commit
fd3e18f18b
@ -583,7 +583,24 @@ transport:
|
|||||||
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
||||||
bind_port: "${COAP_BIND_PORT:5683}"
|
bind_port: "${COAP_BIND_PORT:5683}"
|
||||||
timeout: "${COAP_TIMEOUT:10000}"
|
timeout: "${COAP_TIMEOUT:10000}"
|
||||||
|
dtls:
|
||||||
|
# Enable/disable DTLS 1.2 support
|
||||||
|
enabled: "${COAP_DTLS_ENABLED:false}"
|
||||||
|
# Secure mode. Allowed values: NO_AUTH, X509
|
||||||
|
mode: "${COAP_DTLS_SECURE_MODE:NO_AUTH}"
|
||||||
|
# Path to the key store that holds the certificate
|
||||||
|
key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
|
||||||
|
# Password used to access the key store
|
||||||
|
key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
|
||||||
|
# Password used to access the key
|
||||||
|
key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
|
||||||
|
# Key alias
|
||||||
|
key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
|
||||||
|
# Skip certificate validity check for client certificates.
|
||||||
|
skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
|
||||||
|
x509:
|
||||||
|
dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}"
|
||||||
|
dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}"
|
||||||
swagger:
|
swagger:
|
||||||
api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}"
|
api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}"
|
||||||
security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}"
|
security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}"
|
||||||
|
|||||||
@ -44,6 +44,10 @@
|
|||||||
<groupId>org.eclipse.californium</groupId>
|
<groupId>org.eclipse.californium</groupId>
|
||||||
<artifactId>californium-core</artifactId>
|
<artifactId>californium-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.californium</groupId>
|
||||||
|
<artifactId>scandium</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
|||||||
@ -46,6 +46,10 @@ public class CoapTransportContext extends TransportContext {
|
|||||||
@Value("${transport.coap.timeout}")
|
@Value("${transport.coap.timeout}")
|
||||||
private Long timeout;
|
private Long timeout;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Autowired(required = false)
|
||||||
|
private TbCoapDtlsSettings dtlsSettings;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Autowired
|
@Autowired
|
||||||
private JsonCoapAdaptor jsonCoapAdaptor;
|
private JsonCoapAdaptor jsonCoapAdaptor;
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import org.eclipse.californium.core.observe.ObserveRelation;
|
|||||||
import org.eclipse.californium.core.server.resources.CoapExchange;
|
import org.eclipse.californium.core.server.resources.CoapExchange;
|
||||||
import org.eclipse.californium.core.server.resources.Resource;
|
import org.eclipse.californium.core.server.resources.Resource;
|
||||||
import org.eclipse.californium.core.server.resources.ResourceObserver;
|
import org.eclipse.californium.core.server.resources.ResourceObserver;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
import org.thingsboard.server.common.data.DeviceTransportType;
|
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||||
@ -63,15 +64,22 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
private static final int FEATURE_TYPE_POSITION = 4;
|
private static final int FEATURE_TYPE_POSITION = 4;
|
||||||
private static final int REQUEST_ID_POSITION = 5;
|
private static final int REQUEST_ID_POSITION = 5;
|
||||||
|
|
||||||
|
private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3;
|
||||||
|
private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4;
|
||||||
|
private static final String DTLS_SESSION_ID_KEY = "DTLS_SESSION_ID";
|
||||||
|
|
||||||
private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>();
|
||||||
private final ConcurrentMap<String, AtomicInteger> tokenToNotificationCounterMap = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, AtomicInteger> tokenToNotificationCounterMap = new ConcurrentHashMap<>();
|
||||||
private final Set<UUID> rpcSubscriptions = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> rpcSubscriptions = ConcurrentHashMap.newKeySet();
|
||||||
private final Set<UUID> attributeSubscriptions = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> attributeSubscriptions = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
public CoapTransportResource(CoapTransportContext coapTransportContext, String name) {
|
private ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap;
|
||||||
|
|
||||||
|
public CoapTransportResource(CoapTransportContext coapTransportContext, ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap, String name) {
|
||||||
super(coapTransportContext, name);
|
super(coapTransportContext, name);
|
||||||
this.setObservable(true); // enable observing
|
this.setObservable(true); // enable observing
|
||||||
this.addObserver(new CoapResourceObserver());
|
this.addObserver(new CoapResourceObserver());
|
||||||
|
this.dtlsSessionIdMap = dtlsSessionIdMap;
|
||||||
// this.setObservable(false); // disable observing
|
// this.setObservable(false); // disable observing
|
||||||
// this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs
|
// this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs
|
||||||
// this.getAttributes().setObservable(); // mark observable in the Link-Format
|
// this.getAttributes().setObservable(); // mark observable in the Link-Format
|
||||||
@ -187,14 +195,40 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
Exchange advanced = exchange.advanced();
|
Exchange advanced = exchange.advanced();
|
||||||
Request request = advanced.getRequest();
|
Request request = advanced.getRequest();
|
||||||
|
|
||||||
Optional<DeviceTokenCredentials> credentials = decodeCredentials(request);
|
String dtlsSessionIdStr = request.getSourceContext().get(DTLS_SESSION_ID_KEY);
|
||||||
if (credentials.isEmpty()) {
|
if (!StringUtils.isEmpty(dtlsSessionIdStr)) {
|
||||||
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
|
if (dtlsSessionIdMap != null) {
|
||||||
return;
|
TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionIdMap
|
||||||
|
.computeIfPresent(dtlsSessionIdStr, (dtlsSessionId, dtlsSessionInfo) -> {
|
||||||
|
dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis());
|
||||||
|
return dtlsSessionInfo;
|
||||||
|
});
|
||||||
|
if (tbCoapDtlsSessionInfo != null) {
|
||||||
|
processRequest(exchange, type, request, tbCoapDtlsSessionInfo.getSessionInfoProto(), tbCoapDtlsSessionInfo.getDeviceProfile());
|
||||||
|
} else {
|
||||||
|
exchange.respond(CoAP.ResponseCode.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processAccessTokenRequest(exchange, type, request);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processAccessTokenRequest(exchange, type, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processAccessTokenRequest(CoapExchange exchange, SessionMsgType type, Request request) {
|
||||||
|
Optional<DeviceTokenCredentials> credentials = decodeCredentials(request);
|
||||||
|
if (credentials.isEmpty()) {
|
||||||
|
exchange.respond(CoAP.ResponseCode.UNAUTHORIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(),
|
transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(),
|
||||||
new CoapDeviceAuthCallback(transportContext, exchange, (sessionInfo, deviceProfile) -> {
|
new CoapDeviceAuthCallback(transportContext, exchange, (sessionInfo, deviceProfile) -> {
|
||||||
|
processRequest(exchange, type, request, sessionInfo, deviceProfile);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRequest(CoapExchange exchange, SessionMsgType type, Request request, TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
|
||||||
UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
|
UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
|
||||||
try {
|
try {
|
||||||
TransportConfigurationContainer transportConfigurationContainer = getTransportConfigurationContainer(deviceProfile);
|
TransportConfigurationContainer transportConfigurationContainer = getTransportConfigurationContainer(deviceProfile);
|
||||||
@ -285,7 +319,6 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
log.trace("[{}] Failed to decode message: ", sessionId, e);
|
log.trace("[{}] Failed to decode message: ", sessionId, e);
|
||||||
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
|
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
|
private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
|
||||||
@ -310,7 +343,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
|
|
||||||
private Optional<DeviceTokenCredentials> decodeCredentials(Request request) {
|
private Optional<DeviceTokenCredentials> decodeCredentials(Request request) {
|
||||||
List<String> uriPath = request.getOptions().getUriPath();
|
List<String> uriPath = request.getOptions().getUriPath();
|
||||||
if (uriPath.size() >= ACCESS_TOKEN_POSITION) {
|
if (uriPath.size() > ACCESS_TOKEN_POSITION) {
|
||||||
return Optional.of(new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1)));
|
return Optional.of(new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1)));
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
@ -322,9 +355,12 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
try {
|
try {
|
||||||
if (uriPath.size() >= FEATURE_TYPE_POSITION) {
|
if (uriPath.size() >= FEATURE_TYPE_POSITION) {
|
||||||
return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase()));
|
return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase()));
|
||||||
} else if (uriPath.size() == 3 && uriPath.contains(DataConstants.PROVISION)) {
|
} else if (uriPath.size() >= FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) {
|
||||||
|
if (uriPath.contains(DataConstants.PROVISION)) {
|
||||||
return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase()));
|
return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase()));
|
||||||
}
|
}
|
||||||
|
return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST - 1).toUpperCase()));
|
||||||
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
log.warn("Failed to decode feature type: {}", uriPath);
|
log.warn("Failed to decode feature type: {}", uriPath);
|
||||||
}
|
}
|
||||||
@ -336,6 +372,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
|
|||||||
try {
|
try {
|
||||||
if (uriPath.size() >= REQUEST_ID_POSITION) {
|
if (uriPath.size() >= REQUEST_ID_POSITION) {
|
||||||
return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION - 1)));
|
return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION - 1)));
|
||||||
|
} else {
|
||||||
|
return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION_CERTIFICATE_REQUEST - 1)));
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
log.warn("Failed to decode feature type: {}", uriPath);
|
log.warn("Failed to decode feature type: {}", uriPath);
|
||||||
|
|||||||
@ -19,7 +19,10 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.eclipse.californium.core.CoapResource;
|
import org.eclipse.californium.core.CoapResource;
|
||||||
import org.eclipse.californium.core.CoapServer;
|
import org.eclipse.californium.core.CoapServer;
|
||||||
import org.eclipse.californium.core.network.CoapEndpoint;
|
import org.eclipse.californium.core.network.CoapEndpoint;
|
||||||
|
import org.eclipse.californium.core.network.config.NetworkConfig;
|
||||||
import org.eclipse.californium.core.server.resources.Resource;
|
import org.eclipse.californium.core.server.resources.Resource;
|
||||||
|
import org.eclipse.californium.scandium.DTLSConnector;
|
||||||
|
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -30,6 +33,11 @@ import javax.annotation.PreDestroy;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Service("CoapTransportService")
|
@Service("CoapTransportService")
|
||||||
@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')")
|
@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')")
|
||||||
@ -44,34 +52,53 @@ public class CoapTransportService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CoapTransportContext coapTransportContext;
|
private CoapTransportContext coapTransportContext;
|
||||||
|
|
||||||
|
private TbCoapDtlsCertificateVerifier tbDtlsCertificateVerifier;
|
||||||
|
|
||||||
private CoapServer server;
|
private CoapServer server;
|
||||||
|
|
||||||
|
private ScheduledExecutorService dtlsSessionsExecutor;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() throws UnknownHostException {
|
public void init() throws UnknownHostException {
|
||||||
log.info("Starting CoAP transport...");
|
log.info("Starting CoAP transport...");
|
||||||
log.info("Starting CoAP transport server");
|
log.info("Starting CoAP transport server");
|
||||||
|
|
||||||
this.server = new CoapServer();
|
this.server = new CoapServer();
|
||||||
|
|
||||||
|
CoapEndpoint.Builder capEndpointBuilder = new CoapEndpoint.Builder();
|
||||||
|
|
||||||
|
if (isDtlsEnabled()) {
|
||||||
|
TbCoapDtlsSettings dtlsSettings = coapTransportContext.getDtlsSettings();
|
||||||
|
DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig();
|
||||||
|
DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig);
|
||||||
|
capEndpointBuilder.setConnector(connector);
|
||||||
|
if (dtlsConnectorConfig.isClientAuthenticationRequired()) {
|
||||||
|
tbDtlsCertificateVerifier = (TbCoapDtlsCertificateVerifier) dtlsConnectorConfig.getAdvancedCertificateVerifier();
|
||||||
|
dtlsSessionsExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
dtlsSessionsExecutor.scheduleAtFixedRate(this::evictTimeoutSessions, new Random().nextInt((int) getDtlsSessionReportTimeout()), getDtlsSessionReportTimeout(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
InetAddress addr = InetAddress.getByName(coapTransportContext.getHost());
|
||||||
|
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort());
|
||||||
|
capEndpointBuilder.setInetSocketAddress(sockAddr);
|
||||||
|
capEndpointBuilder.setNetworkConfig(NetworkConfig.getStandard());
|
||||||
|
}
|
||||||
|
CoapEndpoint coapEndpoint = capEndpointBuilder.build();
|
||||||
|
|
||||||
|
server.addEndpoint(coapEndpoint);
|
||||||
|
|
||||||
createResources();
|
createResources();
|
||||||
Resource root = this.server.getRoot();
|
Resource root = this.server.getRoot();
|
||||||
TbCoapServerMessageDeliverer messageDeliverer = new TbCoapServerMessageDeliverer(root);
|
TbCoapServerMessageDeliverer messageDeliverer = new TbCoapServerMessageDeliverer(root);
|
||||||
this.server.setMessageDeliverer(messageDeliverer);
|
this.server.setMessageDeliverer(messageDeliverer);
|
||||||
|
|
||||||
InetAddress addr = InetAddress.getByName(coapTransportContext.getHost());
|
|
||||||
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort());
|
|
||||||
|
|
||||||
CoapEndpoint.Builder coapEndpoitBuilder = new CoapEndpoint.Builder();
|
|
||||||
coapEndpoitBuilder.setInetSocketAddress(sockAddr);
|
|
||||||
CoapEndpoint coapEndpoint = coapEndpoitBuilder.build();
|
|
||||||
|
|
||||||
server.addEndpoint(coapEndpoint);
|
|
||||||
server.start();
|
server.start();
|
||||||
log.info("CoAP transport started!");
|
log.info("CoAP transport started!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createResources() {
|
private void createResources() {
|
||||||
CoapResource api = new CoapResource(API);
|
CoapResource api = new CoapResource(API);
|
||||||
api.add(new CoapTransportResource(coapTransportContext, V1));
|
api.add(new CoapTransportResource(coapTransportContext, getDtlsSessionsMap(), V1));
|
||||||
|
|
||||||
CoapResource efento = new CoapResource(EFENTO);
|
CoapResource efento = new CoapResource(EFENTO);
|
||||||
CoapEfentoTransportResource efentoMeasurementsTransportResource = new CoapEfentoTransportResource(coapTransportContext, MEASUREMENTS);
|
CoapEfentoTransportResource efentoMeasurementsTransportResource = new CoapEfentoTransportResource(coapTransportContext, MEASUREMENTS);
|
||||||
@ -81,8 +108,27 @@ public class CoapTransportService {
|
|||||||
server.add(efento);
|
server.add(efento);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDtlsEnabled() {
|
||||||
|
return coapTransportContext.getDtlsSettings() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConcurrentMap<String, TbCoapDtlsSessionInfo> getDtlsSessionsMap() {
|
||||||
|
return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionIdsMap() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evictTimeoutSessions() {
|
||||||
|
tbDtlsCertificateVerifier.evictTimeoutSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getDtlsSessionReportTimeout() {
|
||||||
|
return tbDtlsCertificateVerifier.getDtlsSessionReportTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
if (dtlsSessionsExecutor != null) {
|
||||||
|
dtlsSessionsExecutor.shutdownNow();
|
||||||
|
}
|
||||||
log.info("Stopping CoAP transport!");
|
log.info("Stopping CoAP transport!");
|
||||||
this.server.destroy();
|
this.server.destroy();
|
||||||
log.info("CoAP transport stopped!");
|
log.info("CoAP transport stopped!");
|
||||||
|
|||||||
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.californium.elements.util.CertPathUtil;
|
||||||
|
import org.eclipse.californium.scandium.dtls.AlertMessage;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateMessage;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateType;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
|
||||||
|
import org.eclipse.californium.scandium.dtls.ConnectionId;
|
||||||
|
import org.eclipse.californium.scandium.dtls.DTLSSession;
|
||||||
|
import org.eclipse.californium.scandium.dtls.HandshakeException;
|
||||||
|
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
|
||||||
|
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
|
||||||
|
import org.eclipse.californium.scandium.util.ServerNames;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
|
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||||
|
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||||
|
import org.thingsboard.server.common.transport.TransportService;
|
||||||
|
import org.thingsboard.server.common.transport.TransportServiceCallback;
|
||||||
|
import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
|
||||||
|
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||||
|
import org.thingsboard.server.common.transport.util.SslUtil;
|
||||||
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
import java.security.cert.CertPath;
|
||||||
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Data
|
||||||
|
public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
|
||||||
|
|
||||||
|
private final TbCoapDtlsSessionInMemoryStorage tbCoapDtlsSessionInMemoryStorage;
|
||||||
|
|
||||||
|
private TransportService transportService;
|
||||||
|
private TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
private boolean skipValidityCheckForClientCert;
|
||||||
|
|
||||||
|
public TbCoapDtlsCertificateVerifier(TransportService transportService, TbServiceInfoProvider serviceInfoProvider, long dtlsSessionInactivityTimeout, long dtlsSessionReportTimeout, boolean skipValidityCheckForClientCert) {
|
||||||
|
this.transportService = transportService;
|
||||||
|
this.serviceInfoProvider = serviceInfoProvider;
|
||||||
|
this.skipValidityCheckForClientCert = skipValidityCheckForClientCert;
|
||||||
|
this.tbCoapDtlsSessionInMemoryStorage = new TbCoapDtlsSessionInMemoryStorage(dtlsSessionInactivityTimeout, dtlsSessionReportTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CertificateType> getSupportedCertificateType() {
|
||||||
|
return Collections.singletonList(CertificateType.X_509);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) {
|
||||||
|
try {
|
||||||
|
String credentialsBody = null;
|
||||||
|
CertPath certpath = message.getCertificateChain();
|
||||||
|
X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]);
|
||||||
|
for (X509Certificate cert : chain) {
|
||||||
|
try {
|
||||||
|
if (!skipValidityCheckForClientCert) {
|
||||||
|
cert.checkValidity();
|
||||||
|
}
|
||||||
|
String strCert = SslUtil.getCertificateString(cert);
|
||||||
|
String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
|
||||||
|
final ValidateDeviceCredentialsResponse[] deviceCredentialsResponse = new ValidateDeviceCredentialsResponse[1];
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||||
|
new TransportServiceCallback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||||
|
if (!StringUtils.isEmpty(msg.getCredentials())) {
|
||||||
|
deviceCredentialsResponse[0] = msg;
|
||||||
|
}
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
latch.await(10, TimeUnit.SECONDS);
|
||||||
|
ValidateDeviceCredentialsResponse msg = deviceCredentialsResponse[0];
|
||||||
|
if (msg != null && strCert.equals(msg.getCredentials())) {
|
||||||
|
credentialsBody = msg.getCredentials();
|
||||||
|
DeviceProfile deviceProfile = msg.getDeviceProfile();
|
||||||
|
if (msg.hasDeviceInfo() && deviceProfile != null) {
|
||||||
|
TransportProtos.SessionInfoProto sessionInfoProto = SessionInfoCreator.create(msg, serviceInfoProvider.getServiceId(), UUID.randomUUID());
|
||||||
|
tbCoapDtlsSessionInMemoryStorage.put(session.getSessionIdentifier().toString(), new TbCoapDtlsSessionInfo(sessionInfoProto, deviceProfile));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException |
|
||||||
|
CertificateEncodingException |
|
||||||
|
CertificateExpiredException |
|
||||||
|
CertificateNotYetValidException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (credentialsBody == null) {
|
||||||
|
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE,
|
||||||
|
session.getPeer());
|
||||||
|
throw new HandshakeException("Certificate chain could not be validated", alert);
|
||||||
|
} else {
|
||||||
|
return new CertificateVerificationResult(cid, certpath, null);
|
||||||
|
}
|
||||||
|
} catch (HandshakeException e) {
|
||||||
|
log.trace("Certificate validation failed!", e);
|
||||||
|
return new CertificateVerificationResult(cid, e, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<X500Principal> getAcceptedIssuers() {
|
||||||
|
return CertPathUtil.toSubjects(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResultHandler(HandshakeResultHandler resultHandler) {
|
||||||
|
// empty implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentMap<String, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionIdsMap() {
|
||||||
|
return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionIdMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictTimeoutSessions() {
|
||||||
|
tbCoapDtlsSessionInMemoryStorage.evictTimeoutSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDtlsSessionReportTimeout() {
|
||||||
|
return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionReportTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Data
|
||||||
|
public class TbCoapDtlsSessionInMemoryStorage {
|
||||||
|
|
||||||
|
private final ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap = new ConcurrentHashMap<>();
|
||||||
|
private long dtlsSessionInactivityTimeout;
|
||||||
|
private long dtlsSessionReportTimeout;
|
||||||
|
|
||||||
|
|
||||||
|
public TbCoapDtlsSessionInMemoryStorage(long dtlsSessionInactivityTimeout, long dtlsSessionReportTimeout) {
|
||||||
|
this.dtlsSessionInactivityTimeout = dtlsSessionInactivityTimeout;
|
||||||
|
this.dtlsSessionReportTimeout = dtlsSessionReportTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String dtlsSessionId, TbCoapDtlsSessionInfo dtlsSessionInfo) {
|
||||||
|
log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", dtlsSessionId, dtlsSessionInfo.getLastActivityTime());
|
||||||
|
dtlsSessionIdMap.putIfAbsent(dtlsSessionId, dtlsSessionInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictTimeoutSessions() {
|
||||||
|
long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout;
|
||||||
|
dtlsSessionIdMap.entrySet().removeIf(entry -> {
|
||||||
|
if (entry.getValue().getLastActivityTime() < expTime) {
|
||||||
|
log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey());
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TbCoapDtlsSessionInfo {
|
||||||
|
|
||||||
|
private TransportProtos.SessionInfoProto sessionInfoProto;
|
||||||
|
private DeviceProfile deviceProfile;
|
||||||
|
private long lastActivityTime;
|
||||||
|
|
||||||
|
|
||||||
|
public TbCoapDtlsSessionInfo(TransportProtos.SessionInfoProto sessionInfoProto, DeviceProfile deviceProfile) {
|
||||||
|
this.sessionInfoProto = sessionInfoProto;
|
||||||
|
this.deviceProfile = deviceProfile;
|
||||||
|
this.lastActivityTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap;
|
||||||
|
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.californium.elements.util.SslContextUtil;
|
||||||
|
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateType;
|
||||||
|
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.server.common.transport.TransportService;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@ConditionalOnProperty(prefix = "transport.coap.dtls", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.coap.enabled}'=='true')")
|
||||||
|
@Component
|
||||||
|
public class TbCoapDtlsSettings {
|
||||||
|
|
||||||
|
@Value("${transport.coap.bind_address}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${transport.coap.bind_port}")
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.mode}")
|
||||||
|
private String mode;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.key_store}")
|
||||||
|
private String keyStoreFile;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.key_store_password}")
|
||||||
|
private String keyStorePassword;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.key_password}")
|
||||||
|
private String keyPassword;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.key_alias}")
|
||||||
|
private String keyAlias;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.skip_validity_check_for_client_cert}")
|
||||||
|
private boolean skipValidityCheckForClientCert;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.x509.dtls_session_inactivity_timeout}")
|
||||||
|
private long dtlsSessionInactivityTimeout;
|
||||||
|
|
||||||
|
@Value("${transport.coap.dtls.x509.dtls_session_report_timeout}")
|
||||||
|
private long dtlsSessionReportTimeout;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TransportService transportService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
|
||||||
|
public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException {
|
||||||
|
Optional<SecurityMode> securityModeOpt = SecurityMode.parse(mode);
|
||||||
|
if (securityModeOpt.isEmpty()) {
|
||||||
|
log.warn("Incorrect configuration of securityMode {}", mode);
|
||||||
|
throw new RuntimeException("Failed to parse mode property: " + mode + "!");
|
||||||
|
} else {
|
||||||
|
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder();
|
||||||
|
configBuilder.setAddress(getInetSocketAddress());
|
||||||
|
String keyStoreFilePath = Resources.getResource(keyStoreFile).getPath();
|
||||||
|
SslContextUtil.Credentials serverCredentials = loadServerCredentials(keyStoreFilePath);
|
||||||
|
SecurityMode securityMode = securityModeOpt.get();
|
||||||
|
if (securityMode.equals(SecurityMode.NO_AUTH)) {
|
||||||
|
configBuilder.setClientAuthenticationRequired(false);
|
||||||
|
configBuilder.setServerOnly(true);
|
||||||
|
} else {
|
||||||
|
configBuilder.setAdvancedCertificateVerifier(
|
||||||
|
new TbCoapDtlsCertificateVerifier(
|
||||||
|
transportService,
|
||||||
|
serviceInfoProvider,
|
||||||
|
dtlsSessionInactivityTimeout,
|
||||||
|
dtlsSessionReportTimeout,
|
||||||
|
skipValidityCheckForClientCert
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
configBuilder.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(),
|
||||||
|
Collections.singletonList(CertificateType.X_509));
|
||||||
|
return configBuilder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SslContextUtil.Credentials loadServerCredentials(String keyStoreFilePath) {
|
||||||
|
try {
|
||||||
|
return SslContextUtil.loadCredentials(keyStoreFilePath, keyAlias, keyStorePassword.toCharArray(),
|
||||||
|
keyPassword.toCharArray());
|
||||||
|
} catch (GeneralSecurityException | IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load serverCredentials due to: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadTrustedCertificates(DtlsConnectorConfig.Builder config, String keyStoreFilePath) {
|
||||||
|
StaticNewAdvancedCertificateVerifier.Builder trustBuilder = StaticNewAdvancedCertificateVerifier.builder();
|
||||||
|
try {
|
||||||
|
Certificate[] trustedCertificates = SslContextUtil.loadTrustedCertificates(
|
||||||
|
keyStoreFilePath, keyAlias,
|
||||||
|
keyStorePassword.toCharArray());
|
||||||
|
trustBuilder.setTrustedCertificates(trustedCertificates);
|
||||||
|
if (trustBuilder.hasTrusts()) {
|
||||||
|
config.setAdvancedCertificateVerifier(trustBuilder.build());
|
||||||
|
}
|
||||||
|
} catch (GeneralSecurityException | IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load trusted certificates due to: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InetSocketAddress getInetSocketAddress() throws UnknownHostException {
|
||||||
|
InetAddress addr = InetAddress.getByName(host);
|
||||||
|
return new InetSocketAddress(addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SecurityMode {
|
||||||
|
X509,
|
||||||
|
NO_AUTH;
|
||||||
|
|
||||||
|
static Optional<SecurityMode> parse(String name) {
|
||||||
|
SecurityMode mode = null;
|
||||||
|
if (name != null) {
|
||||||
|
for (SecurityMode securityMode : SecurityMode.values()) {
|
||||||
|
if (securityMode.name().equalsIgnoreCase(name)) {
|
||||||
|
mode = securityMode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap.client;
|
||||||
|
|
||||||
|
import org.eclipse.californium.core.CoapClient;
|
||||||
|
import org.eclipse.californium.core.CoapResponse;
|
||||||
|
import org.eclipse.californium.core.Utils;
|
||||||
|
import org.eclipse.californium.elements.DtlsEndpointContext;
|
||||||
|
import org.eclipse.californium.elements.EndpointContext;
|
||||||
|
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class NoSecClient {
|
||||||
|
|
||||||
|
private ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||||
|
private CoapClient coapClient;
|
||||||
|
|
||||||
|
public NoSecClient(String host, int port, String accessToken, String clientKeys, String sharedKeys) throws URISyntaxException {
|
||||||
|
URI uri = new URI(getFutureUrl(host, port, accessToken, clientKeys, sharedKeys));
|
||||||
|
this.coapClient = new CoapClient(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
executor.submit(() -> {
|
||||||
|
try {
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
CoapResponse response = null;
|
||||||
|
try {
|
||||||
|
response = coapClient.get();
|
||||||
|
} catch (ConnectorException | IOException e) {
|
||||||
|
System.err.println("Error occurred while sending request: " + e);
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
|
||||||
|
System.out.println(response.getCode() + " - " + response.getCode().name());
|
||||||
|
System.out.println(response.getOptions());
|
||||||
|
System.out.println(response.getResponseText());
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("ADVANCED:");
|
||||||
|
EndpointContext context = response.advanced().getSourceContext();
|
||||||
|
Principal identity = context.getPeerIdentity();
|
||||||
|
if (identity != null) {
|
||||||
|
System.out.println(context.getPeerIdentity());
|
||||||
|
} else {
|
||||||
|
System.out.println("anonymous");
|
||||||
|
}
|
||||||
|
System.out.println(context.get(DtlsEndpointContext.KEY_CIPHER));
|
||||||
|
System.out.println(Utils.prettyPrint(response));
|
||||||
|
} else {
|
||||||
|
System.out.println("No response received.");
|
||||||
|
}
|
||||||
|
Thread.sleep(5000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Error occurred while sending COAP requests.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFutureUrl(String host, Integer port, String accessToken, String clientKeys, String sharedKeys) {
|
||||||
|
return "coap://" + host + ":" + port + "/api/v1/" + accessToken + "/attributes?clientKeys=" + clientKeys + "&sharedKeys=" + sharedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws URISyntaxException {
|
||||||
|
System.out.println("Usage: java -cp ... org.thingsboard.server.transport.coap.client.NoSecClient " +
|
||||||
|
"host port accessToken clientKeys sharedKeys");
|
||||||
|
|
||||||
|
String host = args[0];
|
||||||
|
int port = Integer.parseInt(args[1]);
|
||||||
|
String accessToken = args[2];
|
||||||
|
String clientKeys = args[3];
|
||||||
|
String sharedKeys = args[4];
|
||||||
|
|
||||||
|
NoSecClient client = new NoSecClient(host, port, accessToken, clientKeys, sharedKeys);
|
||||||
|
client.test();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap.client;
|
||||||
|
|
||||||
|
import org.eclipse.californium.core.CoapClient;
|
||||||
|
import org.eclipse.californium.core.CoapResponse;
|
||||||
|
import org.eclipse.californium.core.Utils;
|
||||||
|
import org.eclipse.californium.core.network.CoapEndpoint;
|
||||||
|
import org.eclipse.californium.elements.DtlsEndpointContext;
|
||||||
|
import org.eclipse.californium.elements.EndpointContext;
|
||||||
|
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||||
|
import org.eclipse.californium.elements.util.SslContextUtil;
|
||||||
|
import org.eclipse.californium.scandium.DTLSConnector;
|
||||||
|
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateType;
|
||||||
|
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class SecureClientNoAuth {
|
||||||
|
|
||||||
|
private final DTLSConnector dtlsConnector;
|
||||||
|
private ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||||
|
private CoapClient coapClient;
|
||||||
|
|
||||||
|
public SecureClientNoAuth(DTLSConnector dtlsConnector, String host, int port, String accessToken, String clientKeys, String sharedKeys) throws URISyntaxException {
|
||||||
|
this.dtlsConnector = dtlsConnector;
|
||||||
|
this.coapClient = getCoapClient(host, port, accessToken, clientKeys, sharedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
executor.submit(() -> {
|
||||||
|
try {
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
CoapResponse response = null;
|
||||||
|
try {
|
||||||
|
response = coapClient.get();
|
||||||
|
} catch (ConnectorException | IOException e) {
|
||||||
|
System.err.println("Error occurred while sending request: " + e);
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
|
||||||
|
System.out.println(response.getCode() + " - " + response.getCode().name());
|
||||||
|
System.out.println(response.getOptions());
|
||||||
|
System.out.println(response.getResponseText());
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("ADVANCED:");
|
||||||
|
EndpointContext context = response.advanced().getSourceContext();
|
||||||
|
Principal identity = context.getPeerIdentity();
|
||||||
|
if (identity != null) {
|
||||||
|
System.out.println(context.getPeerIdentity());
|
||||||
|
} else {
|
||||||
|
System.out.println("anonymous");
|
||||||
|
}
|
||||||
|
System.out.println(context.get(DtlsEndpointContext.KEY_CIPHER));
|
||||||
|
System.out.println(Utils.prettyPrint(response));
|
||||||
|
} else {
|
||||||
|
System.out.println("No response received.");
|
||||||
|
}
|
||||||
|
Thread.sleep(5000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Error occurred while sending COAP requests.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoapClient getCoapClient(String host, Integer port, String accessToken, String clientKeys, String sharedKeys) throws URISyntaxException {
|
||||||
|
URI uri = new URI(getFutureUrl(host, port, accessToken, clientKeys, sharedKeys));
|
||||||
|
CoapClient client = new CoapClient(uri);
|
||||||
|
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
|
||||||
|
builder.setConnector(dtlsConnector);
|
||||||
|
|
||||||
|
client.setEndpoint(builder.build());
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFutureUrl(String host, Integer port, String accessToken, String clientKeys, String sharedKeys) {
|
||||||
|
return "coaps://" + host + ":" + port + "/api/v1/" + accessToken + "/attributes?clientKeys=" + clientKeys + "&sharedKeys=" + sharedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws URISyntaxException {
|
||||||
|
System.out.println("Usage: java -cp ... org.thingsboard.server.transport.coap.client.SecureClientNoAuth " +
|
||||||
|
"host port accessToken keyStoreUriPath keyStoreAlias trustedAliasPattern clientKeys sharedKeys");
|
||||||
|
|
||||||
|
String host = args[0];
|
||||||
|
int port = Integer.parseInt(args[1]);
|
||||||
|
String accessToken = args[2];
|
||||||
|
String clientKeys = args[7];
|
||||||
|
String sharedKeys = args[8];
|
||||||
|
|
||||||
|
String keyStoreUriPath = args[3];
|
||||||
|
String keyStoreAlias = args[4];
|
||||||
|
String trustedAliasPattern = args[5];
|
||||||
|
String keyStorePassword = args[6];
|
||||||
|
|
||||||
|
|
||||||
|
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder();
|
||||||
|
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
|
||||||
|
DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
|
||||||
|
SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys);
|
||||||
|
client.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupCredentials(DtlsConnectorConfig.Builder config, String keyStoreUriPath, String keyStoreAlias, String trustedAliasPattern, String keyStorePassword) {
|
||||||
|
StaticNewAdvancedCertificateVerifier.Builder trustBuilder = StaticNewAdvancedCertificateVerifier.builder();
|
||||||
|
try {
|
||||||
|
SslContextUtil.Credentials serverCredentials = SslContextUtil.loadCredentials(
|
||||||
|
keyStoreUriPath, keyStoreAlias, keyStorePassword.toCharArray(), keyStorePassword.toCharArray());
|
||||||
|
Certificate[] trustedCertificates = SslContextUtil.loadTrustedCertificates(
|
||||||
|
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
|
||||||
|
trustBuilder.setTrustedCertificates(trustedCertificates);
|
||||||
|
config.setAdvancedCertificateVerifier(trustBuilder.build());
|
||||||
|
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509));
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
System.err.println("certificates are invalid!");
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("certificates are missing!");
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2021 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.transport.coap.client;
|
||||||
|
|
||||||
|
import org.eclipse.californium.core.CoapClient;
|
||||||
|
import org.eclipse.californium.core.CoapResponse;
|
||||||
|
import org.eclipse.californium.core.Utils;
|
||||||
|
import org.eclipse.californium.core.network.CoapEndpoint;
|
||||||
|
import org.eclipse.californium.elements.DtlsEndpointContext;
|
||||||
|
import org.eclipse.californium.elements.EndpointContext;
|
||||||
|
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||||
|
import org.eclipse.californium.elements.util.SslContextUtil;
|
||||||
|
import org.eclipse.californium.scandium.DTLSConnector;
|
||||||
|
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
|
||||||
|
import org.eclipse.californium.scandium.dtls.CertificateType;
|
||||||
|
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class SecureClientX509 {
|
||||||
|
|
||||||
|
private final DTLSConnector dtlsConnector;
|
||||||
|
private ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||||
|
private CoapClient coapClient;
|
||||||
|
|
||||||
|
public SecureClientX509(DTLSConnector dtlsConnector, String host, int port, String clientKeys, String sharedKeys) throws URISyntaxException {
|
||||||
|
this.dtlsConnector = dtlsConnector;
|
||||||
|
this.coapClient = getCoapClient(host, port, clientKeys, sharedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
executor.submit(() -> {
|
||||||
|
try {
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
CoapResponse response = null;
|
||||||
|
try {
|
||||||
|
response = coapClient.get();
|
||||||
|
} catch (ConnectorException | IOException e) {
|
||||||
|
System.err.println("Error occurred while sending request: " + e);
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
|
||||||
|
System.out.println(response.getCode() + " - " + response.getCode().name());
|
||||||
|
System.out.println(response.getOptions());
|
||||||
|
System.out.println(response.getResponseText());
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("ADVANCED:");
|
||||||
|
EndpointContext context = response.advanced().getSourceContext();
|
||||||
|
Principal identity = context.getPeerIdentity();
|
||||||
|
if (identity != null) {
|
||||||
|
System.out.println(context.getPeerIdentity());
|
||||||
|
} else {
|
||||||
|
System.out.println("anonymous");
|
||||||
|
}
|
||||||
|
System.out.println(context.get(DtlsEndpointContext.KEY_CIPHER));
|
||||||
|
System.out.println(Utils.prettyPrint(response));
|
||||||
|
} else {
|
||||||
|
System.out.println("No response received.");
|
||||||
|
}
|
||||||
|
Thread.sleep(5000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Error occurred while sending COAP requests.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoapClient getCoapClient(String host, Integer port, String clientKeys, String sharedKeys) throws URISyntaxException {
|
||||||
|
URI uri = new URI(getFutureUrl(host, port, clientKeys, sharedKeys));
|
||||||
|
CoapClient client = new CoapClient(uri);
|
||||||
|
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
|
||||||
|
builder.setConnector(dtlsConnector);
|
||||||
|
|
||||||
|
client.setEndpoint(builder.build());
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFutureUrl(String host, Integer port, String clientKeys, String sharedKeys) {
|
||||||
|
return "coaps://" + host + ":" + port + "/api/v1/attributes?clientKeys=" + clientKeys + "&sharedKeys=" + sharedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws URISyntaxException {
|
||||||
|
System.out.println("Usage: java -cp ... org.thingsboard.server.transport.coap.client.SecureClientX509 " +
|
||||||
|
"host port keyStoreUriPath keyStoreAlias trustedAliasPattern clientKeys sharedKeys");
|
||||||
|
|
||||||
|
String host = args[0];
|
||||||
|
int port = Integer.parseInt(args[1]);
|
||||||
|
String clientKeys = args[6];
|
||||||
|
String sharedKeys = args[7];
|
||||||
|
|
||||||
|
String keyStoreUriPath = args[2];
|
||||||
|
String keyStoreAlias = args[3];
|
||||||
|
String trustedAliasPattern = args[4];
|
||||||
|
String keyStorePassword = args[5];
|
||||||
|
|
||||||
|
|
||||||
|
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder();
|
||||||
|
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
|
||||||
|
DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
|
||||||
|
SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys);
|
||||||
|
client.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupCredentials(DtlsConnectorConfig.Builder config, String keyStoreUriPath, String keyStoreAlias, String trustedAliasPattern, String keyStorePassword) {
|
||||||
|
StaticNewAdvancedCertificateVerifier.Builder trustBuilder = StaticNewAdvancedCertificateVerifier.builder();
|
||||||
|
try {
|
||||||
|
SslContextUtil.Credentials serverCredentials = SslContextUtil.loadCredentials(
|
||||||
|
keyStoreUriPath, keyStoreAlias, keyStorePassword.toCharArray(), keyStorePassword.toCharArray());
|
||||||
|
Certificate[] trustedCertificates = SslContextUtil.loadTrustedCertificates(
|
||||||
|
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
|
||||||
|
trustBuilder.setTrustedCertificates(trustedCertificates);
|
||||||
|
config.setAdvancedCertificateVerifier(trustBuilder.build());
|
||||||
|
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509));
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
System.err.println("certificates are invalid!");
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("certificates are missing!");
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,7 +30,7 @@ import org.thingsboard.server.common.transport.TransportService;
|
|||||||
import org.thingsboard.server.common.transport.TransportServiceCallback;
|
import org.thingsboard.server.common.transport.TransportServiceCallback;
|
||||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
import org.thingsboard.server.transport.mqtt.util.SslUtil;
|
import org.thingsboard.server.common.transport.util.SslUtil;
|
||||||
|
|
||||||
import javax.net.ssl.KeyManager;
|
import javax.net.ssl.KeyManager;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
@ -41,7 +41,6 @@ import javax.net.ssl.TrustManagerFactory;
|
|||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
|||||||
@ -66,7 +66,7 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
|
|||||||
import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
|
import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
|
||||||
import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler;
|
import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler;
|
||||||
import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher;
|
import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher;
|
||||||
import org.thingsboard.server.transport.mqtt.util.SslUtil;
|
import org.thingsboard.server.common.transport.util.SslUtil;
|
||||||
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
|||||||
@ -25,7 +25,15 @@ import java.util.UUID;
|
|||||||
public class SessionInfoCreator {
|
public class SessionInfoCreator {
|
||||||
|
|
||||||
public static TransportProtos.SessionInfoProto create(ValidateDeviceCredentialsResponse msg, TransportContext context, UUID sessionId) {
|
public static TransportProtos.SessionInfoProto create(ValidateDeviceCredentialsResponse msg, TransportContext context, UUID sessionId) {
|
||||||
return TransportProtos.SessionInfoProto.newBuilder().setNodeId(context.getNodeId())
|
return getSessionInfoProto(msg, context.getNodeId(), sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportProtos.SessionInfoProto create(ValidateDeviceCredentialsResponse msg, String nodeId, UUID sessionId) {
|
||||||
|
return getSessionInfoProto(msg, nodeId, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransportProtos.SessionInfoProto getSessionInfoProto(ValidateDeviceCredentialsResponse msg, String nodeId, UUID sessionId) {
|
||||||
|
return TransportProtos.SessionInfoProto.newBuilder().setNodeId(nodeId)
|
||||||
.setSessionIdMSB(sessionId.getMostSignificantBits())
|
.setSessionIdMSB(sessionId.getMostSignificantBits())
|
||||||
.setSessionIdLSB(sessionId.getLeastSignificantBits())
|
.setSessionIdLSB(sessionId.getLeastSignificantBits())
|
||||||
.setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits())
|
.setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits())
|
||||||
|
|||||||
@ -13,13 +13,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.thingsboard.server.transport.mqtt.util;
|
package org.thingsboard.server.common.transport.util;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.Base64Utils;
|
import org.springframework.util.Base64Utils;
|
||||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
|
||||||
5
pom.xml
5
pom.xml
@ -1152,6 +1152,11 @@
|
|||||||
<artifactId>californium-core</artifactId>
|
<artifactId>californium-core</artifactId>
|
||||||
<version>${californium.version}</version>
|
<version>${californium.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.californium</groupId>
|
||||||
|
<artifactId>scandium</artifactId>
|
||||||
|
<version>${californium.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
|
|||||||
@ -46,6 +46,24 @@ transport:
|
|||||||
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
||||||
bind_port: "${COAP_BIND_PORT:5683}"
|
bind_port: "${COAP_BIND_PORT:5683}"
|
||||||
timeout: "${COAP_TIMEOUT:10000}"
|
timeout: "${COAP_TIMEOUT:10000}"
|
||||||
|
dtls:
|
||||||
|
# Enable/disable DTLS 1.2 support
|
||||||
|
enabled: "${COAP_DTLS_ENABLED:false}"
|
||||||
|
# Secure mode. Allowed values: NO_AUTH, X509
|
||||||
|
mode: "${COAP_DTLS_SECURE_MODE:NO_AUTH}"
|
||||||
|
# Path to the key store that holds the certificate
|
||||||
|
key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
|
||||||
|
# Password used to access the key store
|
||||||
|
key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
|
||||||
|
# Password used to access the key
|
||||||
|
key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
|
||||||
|
# Key alias
|
||||||
|
key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
|
||||||
|
# Skip certificate validity check for client certificates.
|
||||||
|
skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
|
||||||
|
x509:
|
||||||
|
dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}"
|
||||||
|
dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}"
|
||||||
sessions:
|
sessions:
|
||||||
inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
|
inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
|
||||||
report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
|
report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
|
||||||
|
|||||||
@ -518,7 +518,7 @@ export enum DeviceCredentialsType {
|
|||||||
export const credentialTypeNames = new Map<DeviceCredentialsType, string>(
|
export const credentialTypeNames = new Map<DeviceCredentialsType, string>(
|
||||||
[
|
[
|
||||||
[DeviceCredentialsType.ACCESS_TOKEN, 'Access token'],
|
[DeviceCredentialsType.ACCESS_TOKEN, 'Access token'],
|
||||||
[DeviceCredentialsType.X509_CERTIFICATE, 'MQTT X.509'],
|
[DeviceCredentialsType.X509_CERTIFICATE, 'X.509'],
|
||||||
[DeviceCredentialsType.MQTT_BASIC, 'MQTT Basic']
|
[DeviceCredentialsType.MQTT_BASIC, 'MQTT Basic']
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user