Repository: eclipse/leshan
Pull request #771 (2019-11-08 16:29:08)

Server SHOULD not initiate DTLS connection for device using Queue mode
We consider that initiates a connection (server act as DTLS client to initiate a handshake) does not make sense for QueueMode as if we lost connection device is probably absent.
        


Patch:
diff --git a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointContextUtil.java b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointContextUtil.java
index 00e73015..7885b2bb 100644
--- a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointContextUtil.java
+++ b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointContextUtil.java
@@ -26,7 +26,9 @@ import java.util.regex.Pattern;
 import javax.security.auth.x500.X500Principal;
 
 import org.eclipse.californium.elements.AddressEndpointContext;
+import org.eclipse.californium.elements.DtlsEndpointContext;
 import org.eclipse.californium.elements.EndpointContext;
+import org.eclipse.californium.elements.MapBasedEndpointContext;
 import org.eclipse.californium.elements.auth.PreSharedKeyIdentity;
 import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
 import org.eclipse.californium.elements.auth.X509CertPath;
@@ -71,9 +73,11 @@ public class EndpointContextUtil {
      * Create Californium {@link EndpointContext} from Leshan {@link Identity}.
      * 
      * @param identity The Leshan {@link Identity} to convert.
+     * @param preventConnectionInitiation prevent to initiate a Handshake if there is no DTLS connection.
+     * 
      * @return The corresponding Californium {@link EndpointContext}.
      */
-    public static EndpointContext extractContext(Identity identity) {
+    public static EndpointContext extractContext(Identity identity, boolean preventConnectionInitiation) {
         Principal peerIdentity = null;
         if (identity != null) {
             if (identity.isPSK()) {
@@ -85,6 +89,11 @@ public class EndpointContextUtil {
                 peerIdentity = new X500Principal("CN=" + identity.getX509CommonName());
             }
         }
+
+        if (peerIdentity != null && preventConnectionInitiation) {
+                return new MapBasedEndpointContext(identity.getPeerAddress(), peerIdentity,
+                        DtlsEndpointContext.KEY_HANDSHAKE_MODE, DtlsEndpointContext.HANDSHAKE_MODE_NONE);
+        }
         return new AddressEndpointContext(identity.getPeerAddress(), peerIdentity);
     }
 
diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/request/BindingMode.java b/leshan-core/src/main/java/org/eclipse/leshan/core/request/BindingMode.java
index c4e4da41..03bd0530 100644
--- a/leshan-core/src/main/java/org/eclipse/leshan/core/request/BindingMode.java
+++ b/leshan-core/src/main/java/org/eclipse/leshan/core/request/BindingMode.java
@@ -36,5 +36,17 @@ public enum BindingMode {
     US,
 
     /** UDP with Queue Mode and SMS */
-    UQS
+    UQS;
+
+    public boolean useSMS() {
+        return equals(S) || equals(SQ) || equals(UQS);
+    }
+
+    public boolean useQueueMode() {
+        return equals(UQ) || equals(SQ) || equals(UQS);
+    }
+
+    public boolean useUDP() {
+        return equals(U) || equals(UQ) || equals(UQS);
+    }
 }
diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/bootstrap/CaliforniumLwM2mBootstrapRequestSender.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/bootstrap/CaliforniumLwM2mBootstrapRequestSender.java
index b45c6cdf..b336075a 100644
--- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/bootstrap/CaliforniumLwM2mBootstrapRequestSender.java
+++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/bootstrap/CaliforniumLwM2mBootstrapRequestSender.java
@@ -82,7 +82,7 @@ public class CaliforniumLwM2mBootstrapRequestSender implements LwM2mBootstrapReq
     public <T extends LwM2mResponse> T send(BootstrapSession destination, DownlinkRequest<T> request, long timeoutInMs)
             throws InterruptedException {
         return sender.sendLwm2mRequest(destination.getEndpoint(), destination.getIdentity(), destination.getId(), model,
-                null, request, timeoutInMs);
+                null, request, timeoutInMs, false);
     }
 
     /**
@@ -115,7 +115,7 @@ public class CaliforniumLwM2mBootstrapRequestSender implements LwM2mBootstrapReq
     public <T extends LwM2mResponse> void send(BootstrapSession destination, DownlinkRequest<T> request,
             long timeoutInMs, ResponseCallback<T> responseCallback, ErrorCallback errorCallback) {
         sender.sendLwm2mRequest(destination.getEndpoint(), destination.getIdentity(), destination.getId(), model, null,
-                request, timeoutInMs, responseCallback, errorCallback);
+                request, timeoutInMs, responseCallback, errorCallback, false);
     }
 
     /**
diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CaliforniumLwM2mRequestSender.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CaliforniumLwM2mRequestSender.java
index 9d5cd937..ea732a82 100644
--- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CaliforniumLwM2mRequestSender.java
+++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CaliforniumLwM2mRequestSender.java
@@ -97,7 +97,7 @@ public class CaliforniumLwM2mRequestSender implements LwM2mRequestSender, CoapRe
 
         // Send requests synchronously
         T response = sender.sendLwm2mRequest(destination.getEndpoint(), destination.getIdentity(), destination.getId(),
-                model, destination.getRootPath(), request, timeout);
+                model, destination.getRootPath(), request, timeout, destination.preventServerToInitiateConnection());
 
         // Handle special observe case
         if (response != null && response.getClass() == ObserveResponse.class && response.isSuccess()) {
@@ -149,7 +149,7 @@ public class CaliforniumLwM2mRequestSender implements LwM2mRequestSender, CoapRe
                         }
                         responseCallback.onResponse(response);
                     }
-                }, errorCallback);
+                }, errorCallback, destination.preventServerToInitiateConnection());
     }
 
     /**
@@ -174,7 +174,8 @@ public class CaliforniumLwM2mRequestSender implements LwM2mRequestSender, CoapRe
     @Override
     public Response sendCoapRequest(Registration destination, Request coapRequest, long timeoutInMs)
             throws InterruptedException {
-        return sender.sendCoapRequest(destination.getIdentity(), destination.getId(), coapRequest, timeoutInMs);
+        return sender.sendCoapRequest(destination.getIdentity(), destination.getId(), coapRequest, timeoutInMs,
+                destination.preventServerToInitiateConnection());
     }
 
     /**
@@ -205,7 +206,7 @@ public class CaliforniumLwM2mRequestSender implements LwM2mRequestSender, CoapRe
     public void sendCoapRequest(Registration destination, Request coapRequest, long timeoutInMs,
             CoapResponseCallback responseCallback, ErrorCallback errorCallback) {
         sender.sendCoapRequest(destination.getIdentity(), destination.getId(), coapRequest, timeoutInMs,
-                responseCallback, errorCallback);
+                responseCallback, errorCallback, destination.preventServerToInitiateConnection());
     }
 
     /**
diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilder.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilder.java
index 803f41fe..d07a5d62 100644
--- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilder.java
+++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilder.java
@@ -61,27 +61,20 @@ public class CoapRequestBuilder implements DownlinkRequestVisitor {
     private final String rootPath;
     private final String registrationId;
     private final String endpoint;
+    private final boolean preventConnectionInitiation;
 
     private final LwM2mModel model;
     private final LwM2mNodeEncoder encoder;
 
-    public CoapRequestBuilder(Identity destination, LwM2mModel model, LwM2mNodeEncoder encoder) {
-        this.destination = destination;
-        this.rootPath = null;
-        this.registrationId = null;
-        this.endpoint = null;
-        this.model = model;
-        this.encoder = encoder;
-    }
-
     public CoapRequestBuilder(Identity destination, String rootPath, String registrationId, String endpoint,
-            LwM2mModel model, LwM2mNodeEncoder encoder) {
+            LwM2mModel model, LwM2mNodeEncoder encoder, boolean preventConnectionInitiation) {
         this.destination = destination;
         this.rootPath = rootPath;
         this.endpoint = endpoint;
         this.registrationId = registrationId;
         this.model = model;
         this.encoder = encoder;
+        this.preventConnectionInitiation = preventConnectionInitiation;
     }
 
     @Override
@@ -181,7 +174,7 @@ public class CoapRequestBuilder implements DownlinkRequestVisitor {
     public void visit(BootstrapDeleteRequest request) {
         coapRequest = Request.newDelete();
         coapRequest.setConfirmable(true);
-        EndpointContext context = EndpointContextUtil.extractContext(destination);
+        EndpointContext context = EndpointContextUtil.extractContext(destination, preventConnectionInitiation);
         coapRequest.setDestinationContext(context);
         setTarget(coapRequest, request.getPath());
     }
@@ -190,7 +183,7 @@ public class CoapRequestBuilder implements DownlinkRequestVisitor {
     public void visit(BootstrapFinishRequest request) {
         coapRequest = Request.newPost();
         coapRequest.setConfirmable(true);
-        EndpointContext context = EndpointContextUtil.extractContext(destination);
+        EndpointContext context = EndpointContextUtil.extractContext(destination, preventConnectionInitiation);
         coapRequest.setDestinationContext(context);
 
         // root path
@@ -205,8 +198,8 @@ public class CoapRequestBuilder implements DownlinkRequestVisitor {
         coapRequest.getOptions().addUriPath("bs");
     }
 
-    private final void setTarget(Request coapRequest, LwM2mPath path) {
-        EndpointContext context = EndpointContextUtil.extractContext(destination);
+    protected void setTarget(Request coapRequest, LwM2mPath path) {
+        EndpointContext context = EndpointContextUtil.extractContext(destination, preventConnectionInitiation);
         coapRequest.setDestinationContext(context);
 
         // root path
diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/RequestSender.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/RequestSender.java
index 706c62a9..58a1516f 100644
--- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/RequestSender.java
+++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/RequestSender.java
@@ -107,6 +107,7 @@ public class RequestSender implements Destroyable {
      * @param request The request to send to the client.
      * @param timeoutInMs The response timeout to wait in milliseconds (see
      *        https://github.com/eclipse/leshan/wiki/Request-Timeout)
+     * @param preventConnectionInitiation prevent to initiate a Handshake if there is no DTLS connection.
      * @return the response or <code>null</code> if the timeout expires (see
      *         https://github.com/eclipse/leshan/wiki/Request-Timeout).
      * 
@@ -119,11 +120,11 @@ public class RequestSender implements Destroyable {
      */
     public <T extends LwM2mResponse> T sendLwm2mRequest(final String endpointName, Identity destination,
             String sessionId, final LwM2mModel model, String rootPath, final DownlinkRequest<T> request,
-            long timeoutInMs) throws InterruptedException {
+            long timeoutInMs, boolean preventConnectionInitiation) throws InterruptedException {
 
         // Create the CoAP request from LwM2m request
         CoapRequestBuilder coapClientRequestBuilder = new CoapRequestBuilder(destination, rootPath, sessionId,
-                endpointName, model, encoder);
+                endpointName, model, encoder, preventConnectionInitiation);
         request.accept(coapClientRequestBuilder);
         final Request coapRequest = coapClientRequestBuilder.getRequest();
 
@@ -183,18 +184,20 @@ public class RequestSender implements Destroyable {
      *        <li>or any other RuntimeException for unexpected issue.
      *        </ul>
      *        This callback MUST NOT be null.
+     * @param preventConnectionInitiation prevent to initiate a Handshake if there is no DTLS connection.
      * @throws CodecException if request payload can not be encoded.
      */
     public <T extends LwM2mResponse> void sendLwm2mRequest(final String endpointName, Identity destination,
             String sessionId, final LwM2mModel model, String rootPath, final DownlinkRequest<T> request,
-            long timeoutInMs, ResponseCallback<T> responseCallback, ErrorCallback errorCallback) {
+            long timeoutInMs, ResponseCallback<T> responseCallback, ErrorCallback errorCallback,
+            boolean preventConnectionInitiation) {
 
         Validate.notNull(responseCallback);
         Validate.notNull(errorCallback);
 
         // Create the CoAP request from LwM2m request
         CoapRequestBuilder coapClientRequestBuilder = new CoapRequestBuilder(destination, rootPath, sessionId,
-                endpointName, model, encoder);
+                endpointName, model, encoder, preventConnectionInitiation);
         request.accept(coapClientRequestBuilder);
         final Request coapRequest = coapClientRequestBuilder.getRequest();
 
@@ -235,6 +238,7 @@ public class RequestSender implements Destroyable {
      * @param coapRequest The request to send to the client.
      * @param timeoutInMs The response timeout to wait in milliseconds (see
      *        https://github.com/eclipse/leshan/wiki/Request-Timeout)
+     * @param preventConnectionInitiation prevent to initiate a Handshake if there is no DTLS connection.
      * @return the response or <code>null</code> if the timeout expires (see
      *         https://github.com/eclipse/leshan/wiki/Request-Timeout).
      * 
@@ -243,11 +247,11 @@ public class RequestSender implements Destroyable {
      * @throws RequestCanceledException if the request is cancelled.
      * @throws SendFailedException if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer.
      */
-    public Response sendCoapRequest(Identity destination, String sessionId, Request coapRequest, long timeoutInMs)
-            throws InterruptedException {
+    public Response sendCoapRequest(Identity destination, String sessionId, Request coapRequest, long timeoutInMs,
+            boolean preventConnectionInitiation) throws InterruptedException {
 
         // Define destination
-        EndpointContext context = EndpointContextUtil.extractContext(destination);
+        EndpointContext context = EndpointContextUtil.extractContext(destination, preventConnectionInitiation);
         coapRequest.setDestinationContext(context);
 
         // Send CoAP request synchronously
@@ -292,15 +296,16 @@ public class RequestSender implements Destroyable {
      *        <li>or any other RuntimeException for unexpected issue.
      *        </ul>
      *        This callback MUST NOT be null.
+     * @param preventConnectionInitiation prevent to initiate a Handshake if there is no DTLS connection.
      */
     public void sendCoapRequest(Identity destination, String sessionId, Request coapRequest, long timeoutInMs,
-            CoapResponseCallback responseCallback, ErrorCallback errorCallback) {
+            CoapResponseCallback responseCallback, ErrorCallback errorCallback, boolean preventConnectionInitiation) {
 
         Validate.notNull(responseCallback);
         Validate.notNull(errorCallback);
 
         // Define destination
-        EndpointContext context = EndpointContextUtil.extractContext(destination);
+        EndpointContext context = EndpointContextUtil.extractContext(destination, preventConnectionInitiation);
         coapRequest.setDestinationContext(context);
 
         // Add CoAP request callback
diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/Registration.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/Registration.java
index 5dfb1e92..b06e2f62 100644
--- a/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/Registration.java
+++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/Registration.java
@@ -266,6 +266,15 @@ public class Registration implements Serializable {
         return lastUpdate.getTime() + lifeTimeInSec * 1000 + gracePeriodInSec * 1000;
     }
 
+    /**
+     * @return True if no DTLS handshake must be initiated by the Server for this registration.
+     */
+    public boolean preventServerToInitiateConnection() {
+        // We consider that initiates a connection (act as DTLS client to initiate a handshake) does not make sense for
+        // QueueMode as if we lost connection device is probably absent.
+        return bindingMode.useQueueMode() && bindingMode.useUDP();
+    }
+
     /**
      * @return true if the last registration update was done less than lifetime seconds ago.
      */
@@ -287,7 +296,7 @@ public class Registration implements Serializable {
     }
 
     public boolean usesQueueMode() {
-        return bindingMode.equals(BindingMode.UQ) || bindingMode.equals(BindingMode.UQS);
+        return bindingMode.useQueueMode() && bindingMode.useUDP();
     }
 
     /**


Test patch:
diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java
index 72d586e7..577219e0 100644
--- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java
+++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java
@@ -48,6 +48,7 @@ import org.eclipse.californium.scandium.DTLSConnector;
 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
 import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder;
 import org.eclipse.californium.scandium.dtls.PskPublicInformation;
+import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
 import org.eclipse.leshan.LwM2mId;
 import org.eclipse.leshan.client.californium.LeshanClientBuilder;
 import org.eclipse.leshan.client.object.Device;
@@ -187,13 +188,22 @@ public class SecureIntegrationTestHelper extends IntegrationTestHelper {
     }
 
     public void createPSKClient() {
+        createPSKClient(false);
+    }
+
+    public void createPSKClientUsingQueueMode() {
+        createPSKClient(true);
+    }
+
+    public void createPSKClient(boolean queueMode) {
         ObjectsInitializer initializer = new ObjectsInitializer();
         initializer.setInstancesForObject(LwM2mId.SECURITY,
                 Security.psk(
                         "coaps://" + server.getSecuredAddress().getHostString() + ":"
                                 + server.getSecuredAddress().getPort(),
                         12345, GOOD_PSK_ID.getBytes(StandardCharsets.UTF_8), GOOD_PSK_KEY));
-        initializer.setInstancesForObject(LwM2mId.SERVER, new Server(12345, LIFETIME, BindingMode.U, false));
+        initializer.setInstancesForObject(LwM2mId.SERVER,
+                new Server(12345, LIFETIME, queueMode ? BindingMode.UQ : BindingMode.U, false));
         initializer.setInstancesForObject(LwM2mId.DEVICE, new Device("Eclipse Leshan", MODEL_NUMBER, "12345", "U"));
         initializer.setDummyInstancesForObject(LwM2mId.ACCESS_CONTROL);
         List<LwM2mObjectEnabler> objects = initializer.createAll();
@@ -202,6 +212,8 @@ public class SecureIntegrationTestHelper extends IntegrationTestHelper {
         LeshanClientBuilder builder = new LeshanClientBuilder(getCurrentEndpoint());
         builder.setLocalAddress(clientAddress.getHostString(), clientAddress.getPort());
         builder.setObjects(objects);
+        builder.setDtlsConfig(
+                new DtlsConnectorConfig.Builder().setSupportedCipherSuites(CipherSuite.TLS_PSK_WITH_AES_128_CCM_8));
 
         // set an editable PSK store for tests
         builder.setEndpointFactory(new EndpointFactory() {
diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java
index 3f8c08be..c366acfe 100644
--- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java
+++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java
@@ -31,10 +31,13 @@ import org.eclipse.californium.elements.EndpointContext;
 import org.eclipse.californium.elements.RawData;
 import org.eclipse.californium.elements.auth.PreSharedKeyIdentity;
 import org.eclipse.californium.elements.exception.EndpointMismatchException;
+import org.eclipse.californium.elements.exception.EndpointUnconnectedException;
 import org.eclipse.californium.elements.util.SimpleMessageCallback;
 import org.eclipse.californium.scandium.DTLSConnector;
+import org.eclipse.californium.scandium.dtls.DTLSSession;
 import org.eclipse.leshan.core.request.ReadRequest;
 import org.eclipse.leshan.core.request.exception.SendFailedException;
+import org.eclipse.leshan.core.response.ReadResponse;
 import org.eclipse.leshan.server.registration.Registration;
 import org.eclipse.leshan.server.security.EditableSecurityStore;
 import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
@@ -223,6 +226,72 @@ public class SecurityTest {
 
     }
 
+    @Test
+    public void server_initiates_dtls_handshake() throws NonUniqueSecurityInfoException, InterruptedException {
+        // Create PSK server & start it
+        helper.createServer(); // default server support PSK
+        helper.server.start();
+
+        // Create PSK Client
+        helper.createPSKClient();
+
+        // Add client credentials to the server
+        helper.getSecurityStore()
+                .add(SecurityInfo.newPreSharedKeyInfo(helper.getCurrentEndpoint(), GOOD_PSK_ID, GOOD_PSK_KEY));
+
+        // Check for registration
+        helper.assertClientNotRegisterered();
+        helper.client.start();
+        helper.waitForRegistrationAtServerSide(1);
+        Registration registration = helper.getCurrentRegistration();
+        helper.assertClientRegisterered();
+
+        // Remove DTLS connection at server side.
+        ((DTLSConnector) helper.server.coap().getSecuredEndpoint().getConnector()).clearConnectionState();
+
+        // try to send request
+        ReadResponse readResponse = helper.server.send(registration, new ReadRequest(3), 1000);
+        assertTrue(readResponse.isSuccess());
+
+        // ensure we have a new session for it
+        DTLSSession session = ((DTLSConnector) helper.server.coap().getSecuredEndpoint().getConnector())
+                .getSessionByAddress(registration.getSocketAddress());
+        assertNotNull(session);
+    }
+
+    @Test
+    public void server_does_not_initiate_dtls_handshake_with_queue_mode()
+            throws NonUniqueSecurityInfoException, InterruptedException {
+        // Create PSK server & start it
+        helper.createServer(); // default server support PSK
+        helper.server.start();
+
+        // Create PSK Client
+        helper.createPSKClientUsingQueueMode();
+
+        // Add client credentials to the server
+        helper.getSecurityStore()
+                .add(SecurityInfo.newPreSharedKeyInfo(helper.getCurrentEndpoint(), GOOD_PSK_ID, GOOD_PSK_KEY));
+
+        // Check for registration
+        helper.assertClientNotRegisterered();
+        helper.client.start();
+        helper.waitForRegistrationAtServerSide(1);
+        Registration registration = helper.getCurrentRegistration();
+        helper.assertClientRegisterered();
+
+        // Remove DTLS connection at server side.
+        ((DTLSConnector) helper.server.coap().getSecuredEndpoint().getConnector()).clearConnectionState();
+
+        // try to send request
+        try {
+            helper.server.send(registration, new ReadRequest(3), 1000);
+            fail("Read request SHOULD have failed");
+        } catch (SendFailedException e) {
+            assertTrue(e.getCause() instanceof EndpointUnconnectedException);
+        }
+    }
+
     @Test
     public void registered_device_with_bad_psk_identity_to_server_with_psk() throws NonUniqueSecurityInfoException {
         // Create PSK server & start it
diff --git a/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/observation/ObservationServiceTest.java b/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/observation/ObservationServiceTest.java
index 870d70ef..4bf5a211 100644
--- a/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/observation/ObservationServiceTest.java
+++ b/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/observation/ObservationServiceTest.java
@@ -28,8 +28,6 @@ import org.eclipse.leshan.core.observation.Observation;
 import org.eclipse.leshan.core.request.Identity;
 import org.eclipse.leshan.core.request.ObserveRequest;
 import org.eclipse.leshan.server.californium.CaliforniumTestSupport;
-import org.eclipse.leshan.server.californium.observation.ObservationServiceImpl;
-import org.eclipse.leshan.server.californium.observation.ObserveUtil;
 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
 import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
 import org.eclipse.leshan.server.model.StandardModelProvider;
@@ -142,7 +140,8 @@ public class ObservationServiceTest {
         coapRequest.getOptions().addUriPath(String.valueOf(target.getObjectInstanceId()));
         coapRequest.getOptions().addUriPath(String.valueOf(target.getResourceId()));
         coapRequest.setObserve();
-        coapRequest.setDestinationContext(EndpointContextUtil.extractContext(support.registration.getIdentity()));
+        coapRequest
+                .setDestinationContext(EndpointContextUtil.extractContext(support.registration.getIdentity(), false));
         Map<String, String> context = ObserveUtil.createCoapObserveRequestContext(registration.getEndpoint(),
                 registrationId, new ObserveRequest(target.toString()));
         coapRequest.setUserContext(context);
diff --git a/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilderTest.java b/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilderTest.java
index 19e93e2b..0f4db71c 100644
--- a/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilderTest.java
+++ b/leshan-server-cf/src/test/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilderTest.java
@@ -47,7 +47,6 @@ import org.eclipse.leshan.core.request.ReadRequest;
 import org.eclipse.leshan.core.request.WriteAttributesRequest;
 import org.eclipse.leshan.core.request.WriteRequest;
 import org.eclipse.leshan.core.request.WriteRequest.Mode;
-import org.eclipse.leshan.server.californium.request.CoapRequestBuilder;
 import org.eclipse.leshan.server.registration.Registration;
 import org.eclipse.leshan.server.registration.Registration.Builder;
 import org.eclipse.leshan.tlv.Tlv;
@@ -91,7 +90,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         ReadRequest request = new ReadRequest(3, 0);
         builder.visit(request);
 
@@ -109,7 +108,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         ReadRequest request = new ReadRequest(3, 0, 1);
         builder.visit(request);
 
@@ -124,7 +123,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         ReadRequest request = new ReadRequest(3);
         builder.visit(request);
 
@@ -139,7 +138,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         DiscoverRequest request = new DiscoverRequest(3, 0);
         builder.visit(request);
 
@@ -158,7 +157,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         WriteRequest request = new WriteRequest(Mode.UPDATE, 3, 0, LwM2mSingleResource.newStringResource(4, "value"));
         builder.visit(request);
 
@@ -182,7 +181,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         WriteRequest request = new WriteRequest(3, 0, 14, "value");
         builder.visit(request);
 
@@ -197,7 +196,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         AttributeSet attributes = new AttributeSet(new Attribute(Attribute.MINIMUM_PERIOD, 10L),
                 new Attribute(Attribute.MAXIMUM_PERIOD, 100L));
         WriteAttributesRequest request = new WriteAttributesRequest(3, 0, 14, attributes);
@@ -217,7 +216,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         ExecuteRequest request = new ExecuteRequest(3, 0, 12, "params");
         builder.visit(request);
 
@@ -236,7 +235,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         CreateRequest request = new CreateRequest(12, LwM2mSingleResource.newStringResource(0, "value"));
         builder.visit(request);
 
@@ -259,7 +258,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         CreateRequest request = new CreateRequest(12,
                 new LwM2mObjectInstance(26, LwM2mSingleResource.newStringResource(0, "value")));
         builder.visit(request);
@@ -284,7 +283,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         DeleteRequest request = new DeleteRequest(12, 0);
         builder.visit(request);
 
@@ -302,7 +301,7 @@ public class CoapRequestBuilderTest {
 
         // test
         CoapRequestBuilder builder = new CoapRequestBuilder(reg.getIdentity(), reg.getRootPath(), reg.getId(),
-                reg.getEndpoint(), model, encoder);
+                reg.getEndpoint(), model, encoder, false);
         ObserveRequest request = new ObserveRequest(12, 0);
         builder.visit(request);