com.pushtechnology.diffusion.client.features.control.clients.SecurityControl Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2023 DiffusionData Ltd., All Rights Reserved.
*
* Use is subject to license terms.
*
* NOTICE: All information contained herein is, and remains the
* property of Push Technology. The intellectual and technical
* concepts contained herein are proprietary to Push Technology and
* may be covered by U.S. and Foreign Patents, patents in process, and
* are protected by trade secret or copyright law.
*******************************************************************************/
package com.pushtechnology.diffusion.client.features.control.clients;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import com.pushtechnology.diffusion.client.callbacks.Callback;
import com.pushtechnology.diffusion.client.callbacks.ContextCallback;
import com.pushtechnology.diffusion.client.session.PermissionsException;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.session.SessionClosedException;
import com.pushtechnology.diffusion.client.types.GlobalPermission;
import com.pushtechnology.diffusion.client.types.PathPermission;
import com.pushtechnology.diffusion.client.types.TopicPermission;
/**
* This feature allows a client session to query and update the security store.
* The security store is a persistent database maintained by the server
* containing authorisation rules that control what sessions can do.
*
* Access rights to read and write data and to perform actions on the server are
* controlled by a fixed set of permissions. When a session is opened, the
* server assigns it a set of roles based on the principal used to authenticate.
* The rules in the security store assign each role to a set of permissions.
* Each role can be assigned zero, one, or many permissions. The same permission
* can be assigned to multiple roles. Roles can also include other roles to form
* a role hierarchy, and so inherit permissions from the other roles. Roles are
* defined implicitly by specifying them in permission assignments or inclusion
* relationships; there is no need to explicitly create roles in the security
* store.
*
* Permissions either have 'path' or 'global' scope. {@link GlobalPermission
* Global permissions} apply to actions that are server-wide and not specific to
* a particular path. {@link PathPermission Path permissions} apply to
* hierarchical context, such as a branch of the topic tree or a branch of the
* message path hierarchy.
*
*
Evaluation of global permissions
*
* A session has a global permission if any of its roles are assigned the
* permission.
*
* Evaluation of path permissions
*
* A session has a permission for a path if any of its roles have the permission
* for the path.
*
*
* {@link ScriptBuilder#setPathPermissions Path permissions} can be assigned to
* a role for a path. The permissions are inherited by all descendant paths for
* the role, except paths that have a separate permission assignment for the
* role or that are {@link ScriptBuilder#isolatePath(String) isolated} and their
* descendant paths.
*
*
* {@link ScriptBuilder#setDefaultPathPermissions Default path permissions} can
* be assigned to a role to set permissions at the root of the path hierarchy. A
* default permission assignment applies to all paths without direct or
* inherited path permission assignments, except paths that are
* {@link ScriptBuilder#isolatePath(String) isolated} and their descendant
* paths.
*
*
* The permissions a session has for a path are determined as follows:
*
*
* - If the path has permission assignments for one or more of the sessions
* roles, the applicable permissions are the union of all of the assigned
* permissions.
*
- Otherwise, if the path is not isolated, and its parent path has
* permission assignments for one or more of the sessions roles, the applicable
* permissions are the union of all of the permissions assigned to the parent
* path. This rule is applied recursively, for each remaining parent path.
*
- Otherwise, if the neither the path nor any of its parent paths have
* permission assignments for one of the sessions role or are isolated, the
* applicable permissions are the union of the default permissions assigned to
* each role.
*
- If no applicable permissions are found, the session has no permissions
* for that path.
*
*
* Path permission evaluation prior to Diffusion 6.5
*
* The way path permissions are evaluated changed in Diffusion 6.5. In previous
* releases, permissions assigned to a path for a role blocked the inheritance
* of path permissions assigned to other roles. This made it hard to compose
* authorisation polices for differing roles.
*
*
* The path permissions model was changed in Diffusion 6.5 so the set of
* permissions granted to a session for a path is formed by independently
* evaluating the permissions for each of its roles.
*
*
* In addition, Diffusion 6.5 added the ability to isolate paths. To convert a
* Diffusion 6.4 security store to an equivalent Diffusion 6.5 store, for each
* path in a path permission assignment for a role, add a separate statement to
* isolate the path. This produces a strictly equivalent model, but in practice
* it is typical that many of these path isolation statements can be removed
* without affecting an application's security policy, resulting in a simpler
* configuration.
*
*
Access control
*
* To query the store the session needs {@link GlobalPermission#VIEW_SECURITY
* VIEW_SECURITY} permission and to update the store it needs
* {@link GlobalPermission#MODIFY_SECURITY MODIFY_SECURITY} permission.
*
* Accessing the feature
*
* This feature can be obtained from a {@link Session session} as follows:
*
*
* SecurityControl securityControl = session.feature(SecurityControl.class);
*
*
* @author DiffusionData Limited
* @since 5.3
*/
public interface SecurityControl extends SecurityStoreFeature {
/**
* Obtain the current contents of the security store.
*
* @return a CompletableFuture that completes when a response is received
* from the server.
*
*
* If the request was successful, the CompletableFuture will
* complete successfully with a {@link SecurityConfiguration}
* result.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
*
* - {@link PermissionsException} – if the session does
* not have {@code VIEW_SECURITY} permission;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.0
*/
CompletableFuture getSecurity();
/**
* Obtain the current contents of the security store.
*
* @param callback the operation callback
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void getSecurity(ConfigurationCallback callback);
/**
* Obtain the current contents of the security store, with a contextual
* callback.
*
* @param context the context to pass to the callback, may be null
*
* @param callback the operation callback
*
* @param the context type
*
* @see #getSecurity(ConfigurationCallback)
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void getSecurity(
C context,
ConfigurationContextCallback callback);
/**
* The callback interface for use with
* {@link SecurityControl#getSecurity(ConfigurationCallback) getSecurity}.
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface ConfigurationCallback extends Callback {
/**
* This is called to return the requested security configuration.
*
* @param configuration snapshot of information from the security store
*/
void onReply(SecurityConfiguration configuration);
}
/**
* The contextual callback interface for use with
* {@link SecurityControl#getSecurity(Object, ConfigurationContextCallback)
* getSecurity} .
*
*
* Attaches an arbitrary context object to callback notifications.
*
* @param the context type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface ConfigurationContextCallback extends ContextCallback {
/**
* This is called to return the requested security configuration.
*
* @param configuration snapshot of information from the security store
*
* @param context the context object supplied when making the call
*/
void onReply(
C context,
SecurityConfiguration configuration);
}
/**
* Snapshot of information from the security store.
*
* @see SecurityControl#getSecurity(ConfigurationCallback)
* @see SecurityControl#getSecurity(Object, ConfigurationContextCallback)
*/
interface SecurityConfiguration {
/**
* Returns the default set of roles to be assigned to anonymous
* sessions.
*
* @return set of roles. This may be empty.
*/
Set getRolesForAnonymousSessions();
/**
* Returns the default set of roles to be assigned to named sessions.
*
* @return set of roles. This may be empty.
*/
Set getRolesForNamedSessions();
/**
* Returns a list of the roles defined including their permissions
* assignments and included roles.
*
* @return list of roles
*/
List getRoles();
/**
* Returns the set of isolated paths.
*
* @see ScriptBuilder#isolatePath(String)
* @since 6.5
*/
Set getIsolatedPaths();
}
/**
* Encapsulates the defined details for an individual role.
*/
interface Role {
/**
* Returns the role name.
*
* @return the name
*/
String getName();
/**
* Returns the set of global permissions assigned to the role.
*
* @return the set of global permissions. This may be empty indicating
* that the role has no global permissions assigned.
*/
Set getGlobalPermissions();
/**
* Returns the set of default path permissions assigned to the role.
*
* @return the set of default path permissions. This may be empty
* indicating that the role has no default path permissions
* assigned.
*/
Set getDefaultPathPermissions();
/**
* Returns the set of default path permissions assigned to the role.
*
* @return the set of default path permissions. This may be empty
* indicating that the role has no default path permissions
* assigned.
* @deprecated since 6.5. Use {@link #getDefaultPathPermissions()}
* instead.
*/
@Deprecated
Set getDefaultTopicPermissions();
/**
* Returns a map of path to path permission assignments for the
* role.
*
* @return a map of paths to path permission assignments. The
* returned map may be empty if there are no specific path
* permission assignments for the role. Any individual set of
* permissions may also be empty if the role has explicitly had
* no permissions specified for the path.
*/
Map> getPathPermissions();
/**
* Returns a map of path to path permission assignments for the role.
*
* @return a map of paths to path permission assignments. The returned
* map may be empty if there are no specific path permission
* assignments for the role. Any individual set of permissions
* may also be empty if the role has explicitly had no
* permissions specified for the path.
* @deprecated since 6.5. Use {@link #getPathPermissions()} instead.
*/
@Deprecated
Map> getTopicPermissions();
/**
* Returns a set of roles included within the role.
*
* @return included roles. This may be empty if the role includes no
* other roles.
*/
Set getIncludedRoles();
/**
* Returns an {@link Optional}, if the role is locked this will return
* the name of the principal that can update the role.
*
* @return the locking principal. This will not return a value if the
* role is not locked.
*/
Optional getLockingPrincipal();
}
/**
* Returns a builder that can be used to create scripts for use with
* {@link SecurityStoreFeature#updateStore updateStore}.
*
* @return an initial builder that creates an empty script
*/
ScriptBuilder scriptBuilder();
/**
* A script builder may be used to create a script of commands to apply to
* the security store at the server.
*
* Each method call on the builder adds a line to the script and then the
* script may be built using the {@link ScriptBuilder#script() script}
* method which produces a String script which may be sent to the server
* using {@link SecurityStoreFeature#updateStore updateStore}.
*
* Such a builder may be created using the
* {@link SecurityControl#scriptBuilder() scriptBuilder} method.
*
* From Diffusion 6.5, script builders are no longer immutable. Each builder
* operation mutates this script builder and returns it.
*/
interface ScriptBuilder {
/**
* Sets the roles to be assigned by default to all anonymous sessions.
*
* @param roles the roles to be assigned to anonymous sessions. This may
* be empty which would mean that no roles are to be assigned by
* default to anonymous sessions.
*
* @return this builder, modified to set the roles for
* anonymous sessions
*/
ScriptBuilder setRolesForAnonymousSessions(Set roles);
/**
* Sets the roles to be assigned by default to all named sessions.
*
* @param roles the roles to be assigned to all named sessions. This may
* be empty which would mean that no roles are to be assigned by
* default to named sessions.
*
* @return this builder, modified to set the roles for named
* sessions
*/
ScriptBuilder setRolesForNamedSessions(Set roles);
/**
* Sets the global permissions to be assigned to a role.
*
* @param role the role
*
* @param permissions the global permissions to assign to the role. This
* set may be empty, in which case the role will be assigned no
* global permissions.
*
* @return this builder, modified to set the global
* permissions for the role
*/
ScriptBuilder setGlobalPermissions(
String role,
Set permissions);
/**
* Sets the default path permissions to be assigned to a role.
*
* The role will have the given permissions for all paths unless
* specifically overridden by path-scoped assignments.
*
* @param role the role
*
* @param permissions the default permissions to assigned to the role.
* This may be empty, in which case the role will be
* assigned no default path permissions.
*
* @return this builder, modified to set the default path
* permissions for the role
*/
ScriptBuilder setDefaultPathPermissions(
String role,
Set permissions);
/**
* Sets the default path permissions to be assigned to a role.
*
* The role will have the given permissions for all paths unless
* specifically overridden by path-scoped assignments.
*
* @param role the role
*
* @param permissions the default permissions to assigned to the role.
* This may be empty, in which case the role will be assigned no
* default path permissions.
*
* @return this builder, modified to set the default path
* permissions for the role
* @deprecated since 6.5. Use {@link #setDefaultPathPermissions} instead.
*/
@Deprecated
ScriptBuilder setDefaultTopicPermissions(
String role,
Set permissions);
/**
* Sets specific path permissions to be assigned for a role for a path.
*
* @param role the role
*
* @param path specifies the point in the path hierarchy at which the
* permissions are to be applied for the role
*
* @param permissions the permissions to assign to the role for the
* path. This may be empty, in which case the role will have no
* permissions to the specified path, which is different from not
* having a permission assignment for the path (see
* {@link #removePathPermissions(String, String)}).
*
* @return this builder, modified to set the path permissions
* for the role at the given path in the path hierarchy
*/
ScriptBuilder setPathPermissions(
String role,
String path,
Set permissions);
/**
* Sets specific path permissions to be assigned for a role for a path.
*
* @param role the role
*
* @param path specifies the point in the path hierarchy at which the
* permissions are to be applied for the role
*
* @param permissions the permissions to assign to the role for the
* path. This may be empty, in which case the role will have no
* permissions to the specified path, which is different from not
* having a permission assignment for the path (see
* {@link #removePathPermissions(String, String)}).
*
* @return this builder, modified to set the path permissions
* for the role at the given path in the path hierarchy
* @deprecated since 6.5. Use {@link #setPathPermissions} instead.
*/
@Deprecated
ScriptBuilder setTopicPermissions(
String role,
String path,
Set permissions);
/**
* Set a path not to inherit path permissions from its parent paths or
* the default path permissions.
*
*
* By default, a path without specific
* {@link #setPathPermissions(String, String, Set) path permission
* assignments} inherits the permission assignments from the first
* parent path that has them. If neither the path nor any of its parent
* paths have permission assignments, the
* {@link #setDefaultPathPermissions(String, Set) default path
* permissions are used}.
*
* @param path the path
*
* @return this builder, modified to isolates the given path
* in the path hierarchy
* @since 6.5
*/
ScriptBuilder isolatePath(String path);
/**
* Re-instate inheritance of path permission assignments from parents of
* the given path.
*
* @param path the path
*
* @return this builder, modified to re-instates the
* inheritance of path permission assignments from parents of
* the given path
* @see #isolatePath(String)
* @since 6.5
*/
ScriptBuilder deisolatePath(String path);
/**
* Removes any path permissions previously assigned to a particular path
* for a given role.
*
* This is different from setting no path permissions for the path and
* role. By removing permissions set for a particular branch of the path
* hierarchy, the permissions become inherited from assignments made
* against parent paths in the hierarchy or from the default path
* permissions.
*
* @param role the role from which to remove path permissions
*
* @param path the path for which permissions are to be removed
*
* @return this builder, modified to removes the path
* permissions for the role at the given point in the path
* hierarchy
*/
ScriptBuilder removePathPermissions(String role, String path);
/**
* Removes any path permissions previously assigned to a particular path
* for a given role.
*
* This is different from setting no path permissions for the path and
* role. By removing permissions set for a particular branch of the path
* hierarchy, the permissions become inherited from assignments made
* against parent paths in the hierarchy or from the default path
* permissions.
*
* @param role the role from which to remove path permissions
*
* @param path the path for which permissions are to be removed
*
* @return this builder, modified to removes the path
* permissions for the role at the given point in the path
* hierarchy
* @deprecated since 6.5. Use {@link #removePathPermissions} instead.
*/
@Deprecated
ScriptBuilder removeTopicPermissions(String role, String path);
/**
* Sets the roles that are to be included within a specified role.
*
* @param role the role
*
* @param includedRoles the roles to include. This may be empty, which
* would mean that the given role should not include any other
* roles.
*
* @return this builder, modified to set the given role
* relationship
*/
ScriptBuilder setRoleIncludes(String role, Set includedRoles);
/**
* Restrict a role so it can only be edited by a specific principal.
*
* @param role the role
* @param lockingPrincipal the locking principal
*
* @return this builder, modified to locks a role to a single
* principal that can edit it
*/
ScriptBuilder setRoleLockedByPrincipal(String role, String lockingPrincipal);
/**
* Append all the operations of {@code other} to this ScriptBuilder.
*
* @return a combined script builder
* @since 6.0
*/
ScriptBuilder append(ScriptBuilder other);
/**
* Create a script.
*
* @return the script
*/
String script();
}
}