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.client.sdk.manual;
import java.util.HashSet;
import java.util.Set;
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;
/**
* 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<>();
globalPermissions.add(GlobalPermission.VIEW_SERVER);
globalPermissions.add(GlobalPermission.VIEW_SESSION);
// add the given global permissions to the 'CLIENT' role
scriptBuilder.setGlobalPermissions("CLIENT", globalPermissions);
final Set<PathPermission> pathPermissions = new HashSet<>();
pathPermissions.add(PathPermission.UPDATE_TOPIC);
pathPermissions.add(PathPermission.MODIFY_TOPIC);
// set the given default path permissions for the 'CLIENT' role
scriptBuilder.setDefaultPathPermissions("CLIENT", pathPermissions);
final Set<String> roles = new HashSet<>();
roles.add("TOPIC_CONTROL");
roles.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 .