5.1. Access Control in multi-server environment

LwM2M Client may be connected to more than one LwM2M Server. In such situation, restricting Server access to some part of the data model may be required.

To resolve this problem the LwM2M Specification defines an Access Control Object that allows setting specific access rights on data model Instances either during a Bootstrap Phase or normal runtime by properly authorized LwM2M Server.

In a multi-server environment every Object Instance (except Instances of the Access Control Object) has associated Access Control Instance:

Resource

Resource ID

Meaning of the value

Object ID

0

ID of the Object this instance targets

Object Instance ID

1

Object Instance ID this instance targets (also see the note below)

ACL

2

List of pairs (Short Server ID, Access mask) describing access rights assigned to LwM2M Servers

Access Control Owner

3

Short Server ID of the Server which owns this Access Control Instance (i.e. the one that can modify access rights)

Note

65535 is a special Object Instance ID value reserved for use during the Bootstrap Phase and is valid only in combination with Create access flag.

5.1.1. ACL Resource

ACL Resource of the Access Control Object Instance is populated with pairs of form (Short Server ID, Access mask). Access mask is a combination of the following access flags (combined by bitwise OR operator):

Access flag

Allowed LwM2M Operations

Anjay representation

R (00001 binary)

Read, Observe

ANJAY_ACCESS_MASK_READ

W (00010 binary)

Write

ANJAY_ACCESS_MASK_WRITE

E (00100 binary)

Execute

ANJAY_ACCESS_MASK_EXECUTE

D (01000 binary)

Delete

ANJAY_ACCESS_MASK_DELETE

C (10000 binary)

Create

ANJAY_ACCESS_MASK_CREATE

Note

Discover operation is always allowed and LwM2M protocol does not provide a mechanism for forbidding it.

5.1.2. Note on data-model instances lifetime

Access Control Object also helps in managing Object Instance lifetime. Whenever some Object Instance is orphaned (i.e. no LwM2M Server is an Access Control Owner of the Access Control Instance associated with this Object Instance) it MUST be removed by the Client. Anjay’s pre-implemented Access Control Object does this automatically.

Note

Of course, if necessary, you may implement your own Access Control Object and use it instead. Nonetheless it is worth noting that it is an extremely complex Object to implement in a correct way.

5.1.3. Example usage

In this example, we are going to setup multiple-server environment. We will assign LwM2M Server with SSID 1 the Create permission on the Test Object developed in another tutorial.

Additionally, we will allow both LwM2M Servers to read their respective LwM2M Server Instances.

Note

What we do here is roughly equivalent to Factory Bootstrap phase, which is just one of the bootstrapping options. Same thing could be achieved by a Bootstrap Server, which in conformance with the LwM2M Specification would instantiate Access Control Object, and assign access permissions on its own in a multiple-server environment.

We start with installation of the Access Control, Security Object and Server Object modules:

int result = 0;
if (anjay_access_control_install(anjay)
        || anjay_security_object_install(anjay)
        || anjay_server_object_install(anjay)) {
    result = -1;
}

Then we setup two LwM2M Servers:

// LwM2M Server account with SSID = 1
const anjay_security_instance_t security_instance1 = {
    .ssid = 1,
    .server_uri = "coap://eu.iot.avsystem.cloud:5683",
    .security_mode = ANJAY_SECURITY_NOSEC
};

const anjay_server_instance_t server_instance1 = {
    .ssid = 1,
    .lifetime = 86400,
    .default_min_period = -1,
    .default_max_period = -1,
    .disable_timeout = -1,
    .binding = "U"
};

// LwM2M Server account with SSID = 2
const anjay_security_instance_t security_instance2 = {
    .ssid = 2,
    .server_uri = "coap://127.0.0.1:5683",
    .security_mode = ANJAY_SECURITY_NOSEC
};

const anjay_server_instance_t server_instance2 = {
    .ssid = 2,
    .lifetime = 86400,
    .default_min_period = -1,
    .default_max_period = -1,
    .disable_timeout = -1,
    .binding = "U"
};

// Setup first LwM2M Server
anjay_iid_t server_instance_iid1 = ANJAY_ID_INVALID;
anjay_security_object_add_instance(anjay, &security_instance1,
                                   &(anjay_iid_t) { ANJAY_ID_INVALID });
anjay_server_object_add_instance(anjay, &server_instance1,
                                 &server_instance_iid1);

// Setup second LwM2M Server
anjay_iid_t server_instance_iid2 = ANJAY_ID_INVALID;
anjay_security_object_add_instance(anjay, &security_instance2,
                                   &(anjay_iid_t) { ANJAY_ID_INVALID });
anjay_server_object_add_instance(anjay, &server_instance2,
                                 &server_instance_iid2);

And finally, we are ready to set access lists:

// Make SSID = 1 the owner of the Test object
anjay_access_control_set_owner(anjay, 1234, ANJAY_ID_INVALID,
                               server_instance1.ssid, NULL);

// Set LwM2M Create permission rights for it as well
anjay_access_control_set_acl(anjay, 1234, ANJAY_ID_INVALID,
                             server_instance1.ssid,
                             ANJAY_ACCESS_MASK_CREATE);

// Allow both LwM2M Servers to read their Server Instances
anjay_access_control_set_acl(anjay, 1, server_instance_iid1,
                             server_instance1.ssid, ANJAY_ACCESS_MASK_READ);
anjay_access_control_set_acl(anjay, 1, server_instance_iid2,
                             server_instance2.ssid, ANJAY_ACCESS_MASK_READ);

That way we have ensured an exclusive access of Server with SSID 1 to Test Object (/1234) Instances.

Later on, this Server will be able to set some access rights for other Servers, by writing to proper Access Control Instances (i.e. Instances this Server is an owner of, which corresponds to instances it has created), but that’s outside of the scope of this tutorial. We recommend you to look at the LwM2M Specification for more details on Access Control Object, as well as at our API docs.

Note

Please notice cleanup tag at end of main() function. It is important to delete your own implemented objects after calling anjay_delete(), as during the instance destruction Anjay may still try to refer to object’s data and premature object deletion could be disastrous in effects.

cleanup:
    anjay_delete(anjay);
    delete_test_object(test_obj);
    return result;