Repository: eclipse/leshan
Pull request #71 (2016-02-16 10:27:04)

Fixed Security check for non-secure case
Should fix NPE.
Also added integration test for secure cases.

Signed-off-by: Pierre-Henri Trivier <phtrivier@sierrawireless.com>


Patch:
diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityCheck.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityCheck.java
index b5749c1c..18285037 100644
--- a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityCheck.java
+++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityCheck.java
@@ -38,26 +38,24 @@ public class SecurityCheck {
      * 
      */
     public static boolean checkSecurityInfos(String endpoint, Identity clientIdentity, List<SecurityInfo> securityInfos) {
-
-        // Client is presenting itself as not secure, but we have known Security info ;
-        // we must refuse it.
-        if (!clientIdentity.isSecure() && securityInfos != null && !securityInfos.isEmpty()) {
+        // if this is a secure end-point, we must check that the registering client is using the right identity.
+        if (clientIdentity.isSecure()) {
+            if (securityInfos == null || securityInfos.isEmpty()) {
+                LOG.warn("A client {} without security info try to connect through the secure endpont", endpoint);
+                return false;
+            } else {
+                for (SecurityInfo securityInfo : securityInfos) {
+                    if (checkSecurityInfo(endpoint, clientIdentity, securityInfo)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        } else if (securityInfos != null && !securityInfos.isEmpty()) {
             LOG.warn("client {} must connect using DTLS ", endpoint);
             return false;
         }
-
-        if (clientIdentity.isSecure() && (securityInfos == null || securityInfos.isEmpty())) {
-            LOG.warn("A client {} without security info try to connect through the secure endpont", endpoint);
-            return false;
-        }
-
-        for (SecurityInfo securityInfo : securityInfos) {
-            if (checkSecurityInfo(endpoint, clientIdentity, securityInfo)) {
-                return true;
-            }
-        }
-        return false;
-
+        return true;
     }
 
     /**


Test patch:
diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java
index 009f928c..65535355 100644
--- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java
+++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java
@@ -18,6 +18,7 @@ package org.eclipse.leshan.integration.tests;
 
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.util.Arrays;
 import java.util.List;
 
 import org.eclipse.leshan.LwM2mId;
@@ -26,16 +27,18 @@ import org.eclipse.leshan.client.object.Device;
 import org.eclipse.leshan.client.object.Security;
 import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
 import org.eclipse.leshan.client.resource.ObjectsInitializer;
-import org.eclipse.leshan.core.request.Identity;
 import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
 import org.eclipse.leshan.server.bootstrap.BootstrapConfig.ServerConfig;
 import org.eclipse.leshan.server.bootstrap.BootstrapConfig.ServerSecurity;
 import org.eclipse.leshan.server.bootstrap.BootstrapStore;
 import org.eclipse.leshan.server.bootstrap.SecurityMode;
 import org.eclipse.leshan.server.californium.impl.LwM2mBootstrapServerImpl;
+import org.eclipse.leshan.server.impl.BootstrapAuthServiceImpl;
 import org.eclipse.leshan.server.security.BootstrapAuthService;
 import org.eclipse.leshan.server.security.BootstrapSecurityStore;
 import org.eclipse.leshan.server.security.SecurityInfo;
+import org.eclipse.leshan.util.Charsets;
+import org.eclipse.leshan.util.Hex;
 
 /**
  * Helper for running a server and executing a client against it.
@@ -43,9 +46,13 @@ import org.eclipse.leshan.server.security.SecurityInfo;
  */
 public class BootstrapIntegrationTestHelper extends IntegrationTestHelper {
 
+    // public static final String SECURE_ENDPOINT_IDENTIFIER = "secureclient";
+    public static final String SECURE_PSK_ID = "Client_identity";
+    public static final byte[] SECURE_PSK_KEY = Hex.decodeHex("73656372657450534b".toCharArray());
+
     LwM2mBootstrapServerImpl bootstrapServer;
 
-    public void createBootstrapServer() {
+    public void createBootstrapServer(BootstrapSecurityStore securityStore) {
 
         BootstrapStore bsStore = new BootstrapStore() {
             @Override
@@ -78,24 +85,12 @@ public class BootstrapIntegrationTestHelper extends IntegrationTestHelper {
                 return bsConfig;
             }
         };
-        BootstrapSecurityStore securityStore = new BootstrapSecurityStore() {
-            @Override
-            public SecurityInfo getByIdentity(String identity) {
-                return null;
-            }
 
-            @Override
-            public List<SecurityInfo> getAllByEndpoint(String endpoint) {
-                return null;
-            }
-        };
+        if (securityStore == null) {
+            securityStore = dummyBsSecurityStore();
+        }
 
-        BootstrapAuthService bsAuthService = new BootstrapAuthService() {
-            @Override
-            public boolean authenticate(String endpoint, Identity clientIdentity) {
-                return true;
-            }
-        };
+        BootstrapAuthService bsAuthService = new BootstrapAuthServiceImpl(securityStore);
 
         bootstrapServer = new LwM2mBootstrapServerImpl(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0),
                 new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), bsStore, securityStore, bsAuthService);
@@ -105,10 +100,12 @@ public class BootstrapIntegrationTestHelper extends IntegrationTestHelper {
         ObjectsInitializer initializer = new ObjectsInitializer();
 
         // set only the bootstrap server instance (security)
-        initializer.setInstancesForObject(LwM2mId.SECURITY, new Security("coap://"
-                + bootstrapServer.getNonSecureAddress().getHostString() + ":"
-                + bootstrapServer.getNonSecureAddress().getPort(), true, 3, new byte[0], new byte[0], new byte[0],
-                12345));
+        String bsUrl = "coap://" + bootstrapServer.getNonSecureAddress().getHostString() + ":"
+                + bootstrapServer.getNonSecureAddress().getPort();
+
+        Security security = new Security(bsUrl, true, 3, new byte[0], new byte[0], new byte[0], 12345);
+
+        initializer.setInstancesForObject(LwM2mId.SECURITY, security);
 
         initializer.setInstancesForObject(LwM2mId.DEVICE, new Device("Eclipse Leshan",
                 IntegrationTestHelper.MODEL_NUMBER, "12345", "U"));
@@ -120,4 +117,73 @@ public class BootstrapIntegrationTestHelper extends IntegrationTestHelper {
         client = builder.build();
     }
 
+    public void createPSKClient(String pskIdentity, byte[] pskKey) {
+        ObjectsInitializer initializer = new ObjectsInitializer();
+
+        String bsUrl = "coaps://" + bootstrapServer.getSecureAddress().getHostString() + ":"
+                + bootstrapServer.getSecureAddress().getPort();
+
+        byte[] pskId = pskIdentity.getBytes(Charsets.UTF_8);
+
+        Security security = Security.pskBootstrap(bsUrl, 42, pskId, pskKey);
+
+        initializer.setInstancesForObject(LwM2mId.SECURITY, security);
+
+        initializer.setInstancesForObject(LwM2mId.DEVICE, new Device("Eclipse Leshan",
+                IntegrationTestHelper.MODEL_NUMBER, "12345", "U"));
+        List<LwM2mObjectEnabler> objects = initializer.createMandatory();
+        objects.add(initializer.create(2));
+
+        LeshanClientBuilder builder = new LeshanClientBuilder(ENDPOINT_IDENTIFIER);
+        builder.setObjects(objects);
+        client = builder.build();
+    }
+
+    public static BootstrapSecurityStore bsSecurityStore() {
+
+        return new BootstrapSecurityStore() {
+            @Override
+            public SecurityInfo getByIdentity(String identity) {
+                if (BootstrapIntegrationTestHelper.SECURE_PSK_ID.equals(identity)) {
+                    return pskSecurityInfo();
+                } else {
+                    return null;
+                }
+            }
+
+            @Override
+            public List<SecurityInfo> getAllByEndpoint(String endpoint) {
+                if (IntegrationTestHelper.ENDPOINT_IDENTIFIER.equals(endpoint)) {
+                    SecurityInfo info = pskSecurityInfo();
+                    return Arrays.asList(info);
+                } else {
+                    return Arrays.asList();
+                }
+
+            }
+
+        };
+    }
+
+    public static SecurityInfo pskSecurityInfo() {
+        SecurityInfo info = SecurityInfo.newPreSharedKeyInfo(BootstrapIntegrationTestHelper.ENDPOINT_IDENTIFIER,
+                BootstrapIntegrationTestHelper.SECURE_PSK_ID, BootstrapIntegrationTestHelper.SECURE_PSK_KEY);
+        return info;
+    }
+
+    private BootstrapSecurityStore dummyBsSecurityStore() {
+        return new BootstrapSecurityStore() {
+
+            @Override
+            public SecurityInfo getByIdentity(String identity) {
+                return null;
+            }
+
+            @Override
+            public List<SecurityInfo> getAllByEndpoint(String endpoint) {
+                return null;
+            }
+        };
+    }
+
 }
diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapTest.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapTest.java
index 4ef359b6..42cdf6dc 100644
--- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapTest.java
+++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapTest.java
@@ -15,9 +15,9 @@
  *******************************************************************************/
 package org.eclipse.leshan.integration.tests;
 
-import static org.eclipse.leshan.integration.tests.IntegrationTestHelper.ENDPOINT_IDENTIFIER;
 import static org.junit.Assert.*;
 
+import org.eclipse.leshan.util.Hex;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -32,16 +32,11 @@ public class BootstrapTest {
         helper.createServer();
         helper.server.start();
 
-        // Bootstrap server
-        helper.createBootstrapServer();
-        helper.bootstrapServer.start();
-
-        helper.createClient();
-        helper.client.start();
     }
 
     @After
     public void stop() {
+
         helper.client.stop();
         helper.bootstrapServer.stop();
         helper.server.stop();
@@ -49,10 +44,50 @@ public class BootstrapTest {
 
     @Test
     public void bootstrap() {
-        helper.waitForRegistration(2);
+        // Bootstrap server
+        helper.createBootstrapServer(null);
+        helper.bootstrapServer.start();
+
+        helper.createClient();
+        helper.client.start();
+
+        helper.waitForRegistration(1);
 
         // check the client is registered
         assertEquals(1, helper.server.getClientRegistry().allClients().size());
-        assertNotNull(helper.server.getClientRegistry().get(ENDPOINT_IDENTIFIER));
+        assertNotNull(helper.server.getClientRegistry().get(BootstrapIntegrationTestHelper.ENDPOINT_IDENTIFIER));
+    }
+
+    @Test
+    public void bootstrapSecure() {
+
+        // Bootstrap server
+        helper.createBootstrapServer(BootstrapIntegrationTestHelper.bsSecurityStore());
+        helper.bootstrapServer.start();
+
+        helper.createPSKClient("Client_identity", Hex.decodeHex("73656372657450534b".toCharArray()));
+        helper.client.start();
+
+        helper.waitForRegistration(1);
+
+        assertEquals(1, helper.server.getClientRegistry().allClients().size());
+        assertNotNull(helper.server.getClientRegistry().get(IntegrationTestHelper.ENDPOINT_IDENTIFIER));
     }
+
+    @Test
+    public void bootstrapSecureWithBadCredentials() {
+
+        // Bootstrap server
+        helper.createBootstrapServer(BootstrapIntegrationTestHelper.bsSecurityStore());
+        helper.bootstrapServer.start();
+
+        helper.createPSKClient("Client_identity", Hex.decodeHex("010101010101010101".toCharArray()));
+        helper.client.start();
+
+        helper.waitForRegistration(1);
+
+        assertEquals(0, helper.server.getClientRegistry().allClients().size());
+        assertNull(helper.server.getClientRegistry().get(IntegrationTestHelper.ENDPOINT_IDENTIFIER));
+    }
+
 }