Just a second...

Example: Update the security store

The following examples use the SecurityControl feature in the Diffusion™ API to update the security store.

JavaScript
// Session security allows you to change the principal that a session is authenticated as.
// It also  allows users to query and update server-side security and authentication stores,
// which control users, roles and permissions. This enables you to manage the capabilities
// that any logged in user will have access to.

// Connect to Diffusion with control client credentials
const session = await diffusion.connect({
    host   : 'diffusion.example.com',
    port   : 443,
    secure : true,
    principal : 'control',
    credentials : 'password'
});

// 1. A session change their principal by re-authenticating
await session.security.changePrincipal('admin', 'password');

console.log('Authenticated as admin');

// 2. The security configuration provides details about roles and their assigned permissions
try {
    const config = await session.security.getSecurityConfiguration();
    console.log('Roles for anonymous sessions: ', config.anonymous);
    console.log('Roles for named sessions: ', config.named);
    console.log('Available roles: ', config.roles);
} catch(error) {
    console.log('Unable to fetch security configuration', error);
}

// 3. Changes to the security configuration are done with a SecurityScriptBuilder
const securityScriptBuilder = session.security.securityScriptBuilder();

// Set the permissions for a particular role - global and topic-scoped
// Each method on a script builder returns a new builder
const setPermissionScript = securityScriptBuilder
    .setGlobalPermissions('SUPERUSER', ['REGISTER_HANDLER'])
    .setPathPermissions('SUPERUSER', '/foo', ['UPDATE_TOPIC'])
    .build();

// Update the server-side store with the generated script
try {
    await session.security.updateSecurityStore(setPermissionScript);
    console.log('Security configuration updated successfully');
} catch(error) {
    console.log('Failed to update security configuration: ', error);
}

// 4. The system authentication configuration lists all users & roles
try {
    const config = await session.security.getSystemAuthenticationConfiguration();
    console.log('System principals: ', config.principals);
    console.log('Anonymous sessions: ', config.anonymous);
} catch(error) {
    console.log('Unable to fetch system authentication configuration', error);
}

// 5. Changes to the system authentication config are done with a SystemAuthenticationScriptBuilder
const authenticationScriptBuilder = session.security.authenticationScriptBuilder();

// Add a new user and set password & roles.
const addUserScript = authenticationScriptBuilder
    .addPrincipal('Superman', 'correcthorsebatterystapler')
    .assignRoles('Superman', ['SUPERUSER'])
    .build();

// Update the system authentication store
try {
    await session.security.updateAuthenticationStore(addUserScript);
    console.log('Updated system authentication config');
} catch(error) {
    console.log('Failed to update system authentication: ', error);
}
.NET
/**
 * Copyright © 2021 - 2023 DiffusionData Ltd.
 *
 * 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.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using PushTechnology.ClientInterface.Client.Factories;
using PushTechnology.ClientInterface.Client.Features.Control.Clients.SecurityControl;
using PushTechnology.ClientInterface.Client.Session;
using PushTechnology.ClientInterface.Client.Types;
using static System.Console;

namespace PushTechnology.ClientInterface.Example {
    /// <summary>
    /// Client implementation that demonstrates how to update the security store.
    /// </summary>
    public sealed class SecurityControl
    {
        public async Task SecurityControlExample(string serverUrl)
        {
            // Connect as an admin session
            var session = Diffusion.Sessions.Principal("admin").Password("password")
                .CertificateValidation((cert, chain, errors) => CertificateValidationResult.ACCEPT)
                .Open(serverUrl);

            string role = "ADMINISTRATOR";

            IReadOnlyCollection<GlobalPermission> defaultPermissions = null;
            ISecurityConfiguration securityConfig = null;

            try
            {
                //Get the default global permissions for the Admin role.
                securityConfig = await session.SecurityControl.GetSecurityAsync();

                var adminRole = securityConfig.Roles.Where(x => x.Name == role).FirstOrDefault();
                defaultPermissions = adminRole.GlobalPermissions;

                WriteLine($"The Administrator role has the following global permissions by default:");

                foreach (var permission in defaultPermissions)
                {
                    WriteLine($"'{permission}'");
                }
            }
            catch (Exception ex)
            {
                WriteLine($"Failed to get global permissions : {ex}.");
            }

            try
            {
                //Add the following global permissions for the Admin role.
                var permissions = new List<GlobalPermission>(defaultPermissions);
                permissions.AddRange(new[] { GlobalPermission.REGISTER_HANDLER, 
                                             GlobalPermission.VIEW_SESSION });

                WriteLine($"Adding further permissions...");

                string script = 
                    session.SecurityControl.Script.SetGlobalPermissions(role, permissions).ToScript();

                await session.SecurityControl.UpdateStoreAsync(script);
            }
            catch (Exception ex)
            {
                WriteLine($"Failed to set global permissions : {ex}.");
            }
            finally
            {
                session.Close();
            }
        }
    }
}
Java and Android
/*******************************************************************************
 * Copyright (C) 2023 DiffusionData Ltd.
 *
 * 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 com.pushtechnology.diffusion.manual;

import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.control.clients.SecurityControl;
import com.pushtechnology.diffusion.client.features.control.clients.SecurityControl.ScriptBuilder;
import com.pushtechnology.diffusion.client.features.control.clients.SecurityControl.SecurityConfiguration;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.types.GlobalPermission;
import com.pushtechnology.diffusion.client.types.PathPermission;

import java.util.HashSet;
import java.util.Set;

/**
 * An example of using a control client to alter the security configuration.
 *
 * This uses the 'SecurityControl' feature
 *
 * @author DiffusionData Limited
 */
public final class SecurityControlExample {

    public static void main(String[] args) {

        final Session session = Diffusion.sessions()
            .principal("admin")
            .password("password")
            .open("ws://localhost:8080");

        final SecurityControl securityControl =
            session.feature(SecurityControl.class);

        final ScriptBuilder scriptBuilder = securityControl.scriptBuilder();

        final Set<GlobalPermission> globalPermissions = new HashSet<GlobalPermission>() {{
            add(GlobalPermission.VIEW_SERVER);
            add(GlobalPermission.VIEW_SESSION);
        }};

        // add the given global permissions to the 'CLIENT' role
        scriptBuilder.setGlobalPermissions("CLIENT", globalPermissions);

        final Set<PathPermission> pathPermissions = new HashSet<PathPermission>() {{
            add(PathPermission.UPDATE_TOPIC);
            add(PathPermission.MODIFY_TOPIC);
        }};

        // set the given default path permissions for the 'CLIENT' role
        scriptBuilder.setDefaultPathPermissions("CLIENT", pathPermissions);

        final Set<String> roles = new HashSet<String>() {{
            add("TOPIC_CONTROL");
            add("CLIENT_CONTROL");
        }};

        // include the given roles within the 'OPERATOR' role
        scriptBuilder.setRoleIncludes("OPERATOR", roles);

        // update the security store
        securityControl.updateStore(scriptBuilder.script()).join();

        // get the security configuration and print out all roles
        final SecurityConfiguration configuration = securityControl.getSecurity().join();

        configuration.getRoles().forEach(System.out::println);
        session.close();
    }
}
C
/**
 * Copyright © 2021 - 2023 DiffusionData Ltd.
 *
 * 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.
 */

#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
        #include <unistd.h>
#else
        #define sleep(x) Sleep(1000 * x)
#endif

#include "diffusion.h"


static int on_get_security_store(
        SESSION_T *session,
        const SECURITY_STORE_T store,
        void *context)
{
        char **anonymous_roles = get_security_default_anonymous_roles(store);
        printf("Default anonymous roles: ");
        while (*anonymous_roles != NULL) {
                printf("%s ", *anonymous_roles);
                anonymous_roles++;
        }
        printf("\n");

        char **named_roles = get_security_default_named_roles(store);
        printf("Default named roles: ");
        while (*named_roles != NULL) {
                printf("%s ", *named_roles);
                named_roles++;
        }
        printf("\n");

        char **isolated_paths = get_security_isolated_paths(store);
        printf("Isolated paths: ");
        while (*isolated_paths != NULL) {
                printf("%s ", *isolated_paths);
                isolated_paths++;
        }
        printf("\n");
        return HANDLER_SUCCESS;
}


static int on_update_security_store(
        SESSION_T *session,
        const LIST_T *error_reports,
        void *context)
{
        // security store has been updated
        return HANDLER_SUCCESS;
}


int main(int argc, char **argv)
{
        const char *url = "ws://localhost:8080";
        const char *principal = "admin";
        const char *password = "password";

        CREDENTIALS_T *credentials = credentials_create_password(password);

        SESSION_T *session;
        DIFFUSION_ERROR_T error = { 0 };

        // Create a session, synchronously
        session = session_create(url, principal, credentials, NULL, NULL, &error);
        if(session == NULL) {
                printf("Failed to create session: %s\n", error.message);
                free(error.message);
                credentials_free(credentials);
                return EXIT_FAILURE;
        }

        // Retrieve security store from Diffusion server
        const GET_SECURITY_STORE_PARAMS_T get_params = {
                        .on_get = on_get_security_store,
        };
        get_security_store(session, get_params);

        // Sleep for a while
        sleep(5);

        // update the security store with new path permissions
        SET_T *new_perms = set_new_int(5);
        set_add(new_perms, &SECURITY_PATH_PERMISSIONS_TABLE[PATH_PERMISSION_READ_TOPIC]);
        set_add(new_perms, &SECURITY_PATH_PERMISSIONS_TABLE[PATH_PERMISSION_UPDATE_TOPIC]);

        SCRIPT_T *script = script_create();
        script = update_security_store_default_path_permissions(script, "foo", new_perms);
        set_free(new_perms);

        const UPDATE_SECURITY_STORE_PARAMS_T update_params = {
                        .on_update = on_update_security_store,
                        .update_script = script
        };
        update_security_store(session, update_params);
        script_free(script);

        // Sleep for a while
        sleep(5);

        // Close the session, and release resources and memory
        session_close(session, NULL);
        session_free(session);

        credentials_free(credentials);
        return EXIT_SUCCESS;
}

Change the URL from that provided in the example to the URL of the Diffusion server .