Example: Update the system authentication store
The following examples use the SystemAuthenticationControl feature in the Diffusion™ API to update the system authentication store.
JavaScript
Note: Only steps 4 and 5 deal with the system authentication
store.
// 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 diffusion.connect({ host : 'diffusion.example.com', port : 443, secure : true, principal : 'control', credentials : 'password' }).then(function(session) { // 1. A session change their principal by re-authenticating session.security.changePrincipal('admin', 'password').then(function() { console.log('Authenticated as admin'); }); // 2. The security configuration provides details about roles and their assigned permissions session.security.getSecurityConfiguration().then(function(config) { console.log('Roles for anonymous sessions: ', config.anonymous); console.log('Roles for named sessions: ', config.named); console.log('Available roles: ', config.roles); }, function(error) { console.log('Unable to fetch security configuration', error); }); // 3. Changes to the security configuration are done with a SecurityScriptBuilder var 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 var setPermissionScript = securityScriptBuilder.setGlobalPermissions('SUPERUSER', ['REGISTER_HANDLER']) .setTopicPermissions('SUPERUSER', '/foo', ['UPDATE_TOPIC']) .build(); // Update the server-side store with the generated script session.security.updateSecurityStore(setPermissionScript).then(function() { console.log('Security configuration updated successfully'); }, function(error) { console.log('Failed to update security configuration: ', error); }); // 4. The system authentication configuration lists all users & roles session.security.getSystemAuthenticationConfiguration().then(function(config) { console.log('System principals: ', config.principals); console.log('Anonymous sessions: ', config.anonymous); }, function(error) { console.log('Unable to fetch system authentication configuration', error); }); // 5. Changes to the system authentication config are done with a SystemAuthenticationScriptBuilder var authenticationScriptBuilder = session.security.authenticationScriptBuilder(); // Add a new user and set password & roles. var addUserScript = authenticationScriptBuilder.addPrincipal('Superman', 'correcthorsebatterystapler') .assignRoles('Superman', ['SUPERUSER']) .build(); // Update the system authentication store session.security.updateAuthenticationStore(addUserScript).then(function() { console.log('Updated system authentication config'); }, function(error) { console.log('Failed to update system authentication: ', error); }); });
Java
and Android
package com.pushtechnology.diffusion.examples; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.pushtechnology.diffusion.client.Diffusion; import com.pushtechnology.diffusion.client.features.control.clients.SystemAuthenticationControl; import com.pushtechnology.diffusion.client.features.control.clients.SystemAuthenticationControl.ScriptBuilder; import com.pushtechnology.diffusion.client.session.Session; /** * An example of using a control client to alter the system authentication * configuration. * <P> * This uses the {@link SystemAuthenticationControl} feature only. * * @author Push Technology Limited * @since 5.2 */ public class ControlClientChangingSystemAuthentication { private static final Logger LOG = LoggerFactory.getLogger( ControlClientChangingSystemAuthentication.class); private final SystemAuthenticationControl systemAuthenticationControl; private final ScriptBuilder emptyScript; /** * Constructor. */ public ControlClientChangingSystemAuthentication() { final Session session = Diffusion.sessions() // Authenticate with a user that has the VIEW_SECURITY and // MODIFY_SECURITY permissions. .principal("admin").password("password") // Use a secure channel because we're transferring sensitive // information. .open("wss://diffusion.example.com:80"); systemAuthenticationControl = session.feature(SystemAuthenticationControl.class); emptyScript = systemAuthenticationControl.scriptBuilder(); } /** * For all system users, update the assigned roles to replace the * "SUPERUSER" role and with "ADMINISTRATOR". * * @return a CompletableFuture that completes when the operation succeeds or * fails. * * <p> * If the operation was successful, the CompletableFuture will * complete successfully. * * <p> * Otherwise, the CompletableFuture will complete exceptionally with * an {@link ExecutionException}. See * {@link SystemAuthenticationControl#getSystemAuthentication()} and * {@link SystemAuthenticationControl#updateStore(String)} for * common failure reasons. */ public CompletableFuture<Void> changeSuperUsersToAdministrators() { return systemAuthenticationControl .getSystemAuthentication() .thenCompose(configuration -> { final String script = configuration // For each principal ... .getPrincipals().stream() // ... that has the SUPERUSER assigned role ... .filter(p -> p.getAssignedRoles().contains("SUPERUSER")) // ... create a script that updates the assigned roles to // replace SUPERUSER with ADMINISTRATOR ... .map(p -> { final Set<String> newRoles = new HashSet<>(p.getAssignedRoles()); newRoles.remove("SUPERUSER"); newRoles.add("ADMINISTRATOR"); return emptyScript.assignRoles(p.getName(), newRoles); }) // ... create a single combined script. .reduce(emptyScript, (sb1, sb2) -> sb1.append(sb2)) .script(); LOG.info("Sending the following script to the server:\n{}", script); return systemAuthenticationControl.updateStore(script) // Convert CompletableFuture<?> to // CompletableFuture<Void>. .thenAccept(ignored -> { }); }); } /** * Close the session. */ public void close() { systemAuthenticationControl.getSession().close(); } }
.NET
C
/* * This examples demonstrates how to interact with the system * authentication store. */ #include <stdio.h> #include <apr.h> #include <apr_thread_mutex.h> #include <apr_thread_cond.h> #include "diffusion.h" #include "args.h" #include "service/svc-system-auth-control.h" apr_pool_t *pool = NULL; apr_thread_mutex_t *mutex = NULL; apr_thread_cond_t *cond = NULL; ARG_OPTS_T arg_opts[] = { ARG_OPTS_HELP, {'u', "url", "Diffusion server URL", ARG_OPTIONAL, ARG_HAS_VALUE, "ws://localhost:8080"}, {'p', "principal", "Principal (username) for the connection", ARG_OPTIONAL, ARG_HAS_VALUE, NULL}, {'c', "credentials", "Credentials (password) for the connection", ARG_OPTIONAL, ARG_HAS_VALUE, NULL}, END_OF_ARG_OPTS }; /* * This callback is invoked when the system authentication store is * received, and prints the contents of the store. */ int on_get_system_authentication_store(SESSION_T *session, const SYSTEM_AUTHENTICATION_STORE_T store, void *context) { puts("on_get_system_authentication_store()"); printf("Got %ld principals\n", store.system_principals->size); char **names = get_principal_names(store); for(char **name = names; *name != NULL; name++) { printf("Principal: %s\n", *name); char **roles = get_roles_for_principal(store, *name); for(char **role = roles; *role != NULL; role++) { printf(" |- Role: %s\n", *role); } free(roles); } free(names); switch(store.anonymous_connection_action) { case ANONYMOUS_CONNECTION_ACTION_ALLOW: puts("Allow anonymous connections"); break; case ANONYMOUS_CONNECTION_ACTION_DENY: puts("Deny anonymous connections"); break; case ANONYMOUS_CONNECTION_ACTION_ABSTAIN: puts("Abstain from making anonymous connection decision"); break; } puts("Anonymous connection roles:"); char **roles = get_anonymous_roles(store); for(char **role = roles; *role != NULL; role++) { printf(" |- Role: %s\n", *role); } free(roles); apr_thread_mutex_lock(mutex); apr_thread_cond_broadcast(cond); apr_thread_mutex_unlock(mutex); return HANDLER_SUCCESS; } int main(int argc, char **argv) { /* * Standard command-line parsing. */ const HASH_T *options = parse_cmdline(argc, argv, arg_opts); if(options == NULL || hash_get(options, "help") != NULL) { show_usage(argc, argv, arg_opts); return EXIT_FAILURE; } const char *url = hash_get(options, "url"); const char *principal = hash_get(options, "principal"); CREDENTIALS_T *credentials = NULL; const char *password = hash_get(options, "credentials"); if(password != NULL) { credentials = credentials_create_password(password); } /* * Setup for condition variable */ apr_initialize(); apr_pool_create(&pool, NULL); apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_UNNESTED, pool); apr_thread_cond_create(&cond, pool); /* * Create a session with Diffusion. */ SESSION_T *session; DIFFUSION_ERROR_T error = { 0 }; session = session_create(url, principal, credentials, NULL, NULL, &error); if(session == NULL) { fprintf(stderr, "TEST: Failed to create session\n"); fprintf(stderr, "ERR : %s\n", error.message); return EXIT_FAILURE; } /* * Request the system authentication store. */ const GET_SYSTEM_AUTHENTICATION_STORE_PARAMS_T params = { .on_get = on_get_system_authentication_store }; apr_thread_mutex_lock(mutex); get_system_authentication_store(session, params); apr_thread_cond_wait(cond, mutex); apr_thread_mutex_unlock(mutex); /* * Close the session and tidy up. */ session_close(session, NULL); session_free(session); apr_thread_mutex_destroy(mutex); apr_thread_cond_destroy(cond); apr_pool_destroy(pool); apr_terminate(); return EXIT_SUCCESS; }
Change the URL from that provided in the example to the URL of the Diffusion server.