UNPKG

diffusion

Version:

Diffusion JavaScript client

718 lines (672 loc) 29.3 kB
var _interface = require('util/interface')._interface; /** * Security functionality. Allows querying and modification of server-side security and authentication configuration. * * @example * // Get a reference to the security feature * var security = session.security; * * @namespace Session.security */ /** * A principal in the system authentication store. * * @typedef {Object} Session.security.SystemPrincipal * @property {String} name The principal name * @property {String[]} roles The principal's assigned roles */ var SystemPrincipal = _interface('SystemPrincipal', ['name', 'roles']); /** * Permissions that are applied globally. Allowed values are: * <P> * <ul> * <li><code>AUTHENTICATE</code> - Add an authentication handler</li> * <li><code>VIEW_SESSION</code> - List or listen to client sessions</li> * <li><code>MODIFY_SESSION</code> - Alter a client session.</li> * <li><code>REGISTER_HANDLER</code> - Required to register any server-side handler</li> * <li><code>VIEW_SERVER</code> - View the server's runtime state</li> * <li><code>CONTROL_SERVER</code> - Change the server's runtime state</li> * <li><code>VIEW_SECURITY</code> - Read the security configuration</li> * <li><code>MODIFY_SECURITY</code> - Change the security configuration</li> * </ul> * * @typedef {String} Session.security.GlobalPermission */ /** * Permissions that are applied on a topic path. Allowed values are: * <P> * <ul> * <li><code>SELECT_TOPIC</code> - Use a topic selector that selects the topic path. * <p> * A session must have this permission for the path prefix of any topic selector * used to subscribe or fetch. * <p> * When the subscription or fetch request completes, the resulting topics * are further filtered based on the <code>READ_TOPIC</code> permission. * <p> * A session that has <code>READ_TOPIC</code> but not * <code>SELECT_TOPIC</code> for a particular topic path cannot * subscribe directly to topics belonging to the path. However, the session can * be independently subscribed by a control session that has the * <code>MODIFY_SESSION</code> global permission in addition to the * appropriate <code>SELECT_TOPIC</code> permission. * * </li> * <li><code>READ_TOPIC</code> - Required to receive information from a topic. * <p> * If a session does not have read_topic permission for a topic, the topic * will be excluded from the results of subscription or fetch operations for * the session, and the topic's details cannot be retrieved by the session. * * </li> * <li><code>UPDATE_TOPIC</code> - Update topics</li> * <li><code>MODIFY_TOPIC</code> - Add or remove topics</li> * <li><code>SEND_TO_SESSION</code> - Send a message another session</li> * <li><code>SEND_TO_MESSAGE_HANDLER</code> - Send a message to a handler registered with the server</li> * </ul> * * @typedef {String} Session.security.TopicPermission */ /** * Details for the permissions contained by a single role. * * @typedef Session.security.Role * @property {String} name The name of the role * @property {Session.security.GlobalPermission[]} global The list of global permissions * @property {Session.security.TopicPermission[]} default The list of default topic permissions * @property {Object.<String, Session.security.TopicPermission[]>} topic The map of topic paths to sets of Topic * permissions * @property {String[]} inherits The set of roles that this role inherits from */ var Role = _interface('Role', ['name', 'global', 'default', 'topic', 'inherits']); /** * A snapshot of information from the security store. * * @typedef Session.security.SecurityConfiguration * @property {String[]} named The list of default roles for named sessions * @property {String[]} anonymous The list of default roles for anonymous sessions * @property {Session.security.Role[]} roles The list of all defined roles */ var SecurityConfiguration = _interface('SecurityConfiguration', ['named', 'anonymous', 'roles']); /** * A snapshot of information from the system authentication store. * * @typedef Session.security.SystemAuthenticationConfiguration * @property {Session.security.SystemPrincipal[]} principals The system principals stored on the server. * @property {Object} anonymous The configuration used for anonymous connections. * @property {String} anonymous.action The default action to apply to anonymous connections. * <p> * May be one of: * <ul> * <li><code>deny</code> - Deny anonymous connection attempts.</li> * <li><code>allow</code> - Accept anonymous connection attempts.</li> * <li><code>abstain</code> - Defer authentication for anonymous connection * attempts to subsequent authentication handlers</li> * </ul> * @property {String[]} anonymous.roles - The roles assigned to anonymous connections. */ var SystemAuthenticationConfiguration = _interface('SystemAuthenticationConfiguration', ['principals', 'anonymous']); /** * A builder that can be used to create scripts for use with {@link Session.security#updateStore}. * <P> * Facilitates producing scripts that control the assigment of permissions to roles. * * @class SecurityScriptBuilder */ var SecurityScriptBuilder = _interface('SecurityScriptBuilder', [ /** * Create the script string. * * @return {String} The script * @function SecurityScriptBuilder#build */ 'build', /** * Sets the roles to be assigned by default to all anonymous sessions. * * @param {String[]} [roles=[]] - The roles to be assigned. An empty array, or no argument, will result in anonymous * sessions being assigned no roles by default. * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setRolesForAnonymousSessions */ 'setRolesForAnonymousSessions', /** * Sets the roles to be assigned by default to all sessions that authenticate with a principal. * * @param {String[]} [roles=[]] - The roles to be assigned. Any empty array, or no argument, will result in named * sessions being assigned no roles by default. * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setRolesForNamedSession */ 'setRolesForNamedSessions', /** * Set the global permissions assigned to a particular role. * * @param {String} role - The role to set global permissions for. * @param {String[]} [permissions=[]] - The permissions to assign globally for a role. * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setGlobalPermissions */ 'setGlobalPermissions', /** * Set the default permissions that a particular role will have for topics. * * @param {String} role - The role to set topic permissions for. * @param {String[]} [permissions=[]] - The topic permissions to assign for the role. * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setDefaultTopicPermissions */ 'setDefaultTopicPermissions', /** * Remove any previously assigned permissions from a particular topic for a given role. * <P> * This is different from setting no permissions to a topic. By removing permissions set for a topic, permissions * will be inherited from the nearest set of permissions that have been assigned higher in the topic path hierarchy * or from the default topic permissions if no more specific permissions are found. * * @param {String} role - The role to remove topic permissions from. * @param {String} path - The topic path to remove permissions from. * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#removeTopicPermissions */ 'removeTopicPermissions', /** * Sets specific topic permissions for a named role. * <P> * When permissions are assigned to a role for a topic path they will apply to the topic and any topics below the * specified path. Topic-scoped permissions are assigned to roles for specific topic paths. The permission * assignment applies to all descendant topics, unless there is a more specific assignment. * <P> * To evaluate whether a session has permission for a topic, the server starts at that topic and searches up the * tree to find the nearest permissions assignment. The first assignment is the only one considered, even if the * session has roles involved in assignments further up the hierarchy. * * @param {String} role - The role to assign permissions for. * @param {String} path - The topic path to assign permissions. * @param {String[]} permissions - The permissions to assign to the role for the specified path. Any empty array or * no argument would specify that the role has no permissions at this path, which differs from there being no * permissions assigned for that path (see {@link SecurityScriptBuilder#removeTopicPermissions}). * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setTopicPermissions */ 'setTopicPermissions', /** * Specify a set of a roles that another role should inherit permissions from. * * @param {String} role - The role * @param {String[]} [roles=[]] - The set of roles to inherit from. * * @return {SecurityScriptBuilder} * * @function SecurityScriptBuilder#setRoleIncludes */ 'setRoleIncludes' ]); /** * Additional information supplied to the server upon a successful authentication. * * @typedef AuthenticationHandler.Callback.AuthenticationResult * @property {Array<String>} roles - Additional roles to be assigned to the authenticated session * @property {Object<String,String>} properties - Additional properties to be assigned to the authenticated session */ /** * Handler for session authentication events. Must be implemented by user. * <p> * Authentication handlers implementing this interface can be registered with * the server. The server calls the authentication handlers when a client * application creates a session, or changes the principal associated with a * session, allowing the handler to veto individual requests. * <P> * Authentication handlers are configured in precedence order. Authentication * will succeed if a handler returns * {@link AuthenticationHandler.Callback#allow() allow} and all higher * precedence handlers (earlier in the order) return * {@link AuthenticationHandler.Callback#abstain() abstain}. Authentication * will fail if a handler returns {@link AuthenticationHandler.Callback#deny() deny} * and all higher precedence handlers return 'abstain'. If all authentication * handlers return 'abstain', the request will be denied. Once the outcome is known, * the server may choose not to call the remaining handlers. * <P> * The special variant of {@link AuthenticationHandler.Callback#allow(AuthenticationResult)} * may be used by the handler to supply the server with additional information that is * used to set up the session. * * @class AuthenticationHandler */ var AuthenticationHandler = _interface('AuthenticationHandler', [ /** * Request authentication. * <P> * The server calls this to authenticate new sessions, and when a client * requests the session principal is changed (e.g. using * {@link Session.security#changePrincipal}. * <P> * For each call to <pre>onAuthenticate</pre>, the authentication handler should * respond by calling one of the methods of the provided <code>callback</code>. * The handler may return immediately and process the authentication request * asynchronously. The client session will be blocked until a callback * method is called. * * @param {String} principal - the requested principal, or '' if none was supplied. * @param {String|Buffer} credentials - credentials authenticating the principal * @param {SessionDetails} sessionDetails - the information the server has about the client * @param {AuthenticationHandler.Callback} callback - single use callback * @function AuthenticationHandler#onAuthenticate */ 'onAuthenticate', /** * Called when the handler has been successfully registered with the server. * <P> * A session can register a single handler. If there is already a handler registered, the operation will fail and * {@link AuthenticationHandler#onClose onClose} will be called. * <P> * To deregister the handler, call the <pre>deregister</pre> function supplied. * * @param {Function} deregister - A function that may be called to deregister this handler * * @function AuthenticationHandler#onActive */ 'onActive', /** * Called when the handler is closed. The handler will be closed if the session is closed, or if the handler is * unregistered. * <P> * Once closed, no further calls will be made for the handler. * * @function AuthenticationHandler#onClose */ 'onClose', /** * Notification of a contextual error related to this handler. This is * analogous to an unchecked exception being raised. Situations in which * <code>onError</code> is called include the session being closed before the * handler is registered, a communication timeout, or a problem with the * provided parameters. No further calls will be made to this handler. * * @param {Object} error - The error * * @function AuthenticationHandler#onError */ 'onError' ]); /** * Single-use callback provided to the {@link AuthenticationHandler#onAuthenticate onAuthenticate} call. * <P> * The server calls the handlers for each authentication request. Each * handler must respond {@link AuthenticationHandler.Callback##allow() allow}, * {@link AuthenticationHandler.Callback##abstain() abstain}, * or {@link AuthenticationHandler.Callback#deny() deny}. * <P> * The handler may provide additional information to the allow method with a user-supplied * {@link AuthenticationHandler.Callback.AuthenticationResult AuthenticationResult} object. * <P> * Authentication handlers are configured in precedence order. * Authentication will succeed if a handler returns "allow" and all higher * precedence handlers (earlier in the order) return "abstain". * Authentication will fail if a handler returns "deny" and all higher * precedence handlers return "abstain". If all authentication handlers * return "abstain", the request will be denied. Once the outcome is known, * the server may choose not to call the remaining handlers. * * @class AuthenticationHandler.Callback */ AuthenticationHandler.Callback = _interface('AuthenticationHandlerCallback', [ /** * Authentication passed - allow the authentication request * * @example * // Basic allow * callback.allow(); * * @example * // Allow with AuthenticationResult * callback.allow({ * roles : ['SOME_ROLE'], * properties : { * MyPropertyKey : 'MyPropertyValue' * } * }); * * @param {AuthenticationHandler.Callback.AuthenticationResult} [result] - Optional roles/properties to assign to * the authenticated session * @function AuthenticationHandler.Callback#allow */ 'allow', /** * @function AuthenticationHandler.Callback#abstain */ 'abstain', /** * Authentication failed - deny the authentication request. * @function AuthenticationHandler.Callback#deny */ 'deny' ]); /** * A builder that can be used to create scripts for use with {@link Session.security#updateSystemAuthentication}. * <p> * Facilitates producing scripts that contain the mapping of roles to specific principals/passwords. * * @class SystemAuthenticationScriptBuilder */ var SystemAuthenticationScriptBuilder = _interface('SystemAuthenticationScriptBuilder', [ /** * Create the script string. * * @return {String} The script * @function SystemAuthenticationScriptBuilder#build */ 'build', /** * Change a principal's assigned roles. * * @function Session.security.ScriptBuilder#assignRoles * @param {String} principal - The principal name. * @param {String[]} roles - An array of roles * @return {SystemAuthenticationScriptBuilder} A new builder containing the changed roles * @function SystemAuthenticationScriptBuilder#assignRoles */ 'assignRoles', /** * Add a principal. * * @function ScriptBuilder#addPrincipal * @param {String} principal - The principal name * @param {String} password - The principal's password * @param {String[]} [roles=[]] - The assigned roles for the principal * @return {SystemAuthenticationScriptBuilder} A new builder containing the new principal * @function SystemAuthenticationScriptBuilder#addPrincipal */ 'addPrincipal', /** * Set a principal's password. * * @function ScriptBuilder#setPassword * @param {String} principal - The principal name * @param {String} password - The principal's password * @return {SystemAuthenticationScriptBuilder} A new builder containing the changed password */ 'setPassword', /** * Assert that a principal's password is <code>password</code>. * <p> * This command doesn't update the store. It can be used in conjunction with * {@link SystemAuthenticationScriptBuilder#setPassword} to create a script that updates a * password only if the previous password is supplied. * * @function ScriptBuilder#verifyPassword * @param {String} principal - The principal name * @param {String} password - The principal's password * @return {SystemAuthenticationScriptBuilder} A new builder containing the verification command * @function SystemAuthenticationScriptBuilder#verifyPassword */ 'verifyPassword', /** * Remove a principal. * * @function ScriptBuilder#removePrincipal * @param {String} principal - The principal name * @return {SystemAuthenticationScriptBuilder} A new builder containing the remove command * @function SystemAuthenticationScriptBuilder#removePrincipal */ 'removePrincipal', /** * Instruct the system authentication to allow anonymous connections. * * @function ScriptBuilder#allowAnonymousConnections * @param {String[]} [roles=[]] - The roles to assign to anonymous sessions * @return {SystemAuthenticationScriptBuilder} A new builder containing the allow anonymous connections command. * @function SystemAuthenticationScriptBuilder#allowAnonymousConnections */ 'allowAnonymousConnections', /** * Instruct the system authentication to deny anonymous connections. * * @function ScriptBuilder#denyAnonymousConnections * @return {SystemAuthenticationScriptBuilder} A new builder containing the deny anonymous connections command. * @function SystemAuthenticationScriptBuilder#denyAnonymousConnections */ 'denyAnonymousConnections', /** * Instruct the system authentication handler to defer authentication * decisions for anonymous connections to subsequent handlers. * * @function ScriptBuilder#abstainAnonymousConnections * @return {SystemAuthenticationScriptBuilder} A new builder containing the abstain anonymous connections command. * @function SystemAuthenticationScriptBuilder#abstainAnonymousConnections */ 'abstainAnonymousConnections' ]); var Security = _interface('Security', [ /** * Get the principal that the session is currently authenticated as. * * @returns {String} The session's principal * @function Session.security#getPrincipal */ 'getPrincipal', /** * Change the principal associated with this session. * <P> * <br/> * Allows a session to authenticate as a different principal. If the authentication fails, the current principal * remains valid. * * @param {String} principal - The new principal to use. * @param {String} credentials - Credentials to authenticate the principal with. * @returns {Result<undefined>} A {@link Result<undefined>}. * @function Session.security#changePrincipal * * @example * session.security.changePrincipal('foo', 'password'); * */ 'changePrincipal', /** * Obtain the current contents of the server's security store. * <P> * <br /> * If the request is successful, the result will complete with a {@link Session.security.SecurityConfiguration}. * * @returns {Result<Session.security.SecurityConfiguration>} A * {@link Result<Session.security.SecurityConfiguration>}. * @function Session.security#getSecurityConfiguration * * @example * session.security.getSecurityConfiguration().then(function(configuration) { * console.log('Got security configuration', configuration); * }, function(err) { * console.log('Error getting security configuration', err); * }); * */ 'getSecurityConfiguration', /** * Obtain the current contents of the server's authentication store. * <p> * <br /> * If the request is successful, the success callback will be called with a {@link * Session.security.SystemAuthenticationConfiguration} * object. * <P> * @returns {Result<Session.security.SystemAuthenticationConfiguration>} A * {@link Result<Session.security.SystemAuthenticationConfiguration>}. * * @function Session.security#getSystemAuthenticationConfiguration * * @example * session.security.getSystemAuthenticationConfiguration().then(function(configuration) { * // Display principals/roles * configuration.principals.forEach(function(principal) { * console.log(principal.name, principal.roles); * }); * * // Check the authentication action applied to anonymous connections * console.log(configuration.anonymous.action); * * // Check the default roles assigned to anonymous connections * console.log(configuration.anonymous.roles); * }, function(err) { * // Error retrieving configuration * console.log(err); * }); */ 'getSystemAuthenticationConfiguration', /** * Send a command script to the server to update the security store. The script may be produced by the * builder {@link SecurityScriptBuilder}. * <P> * If the script is applied without error to the server, the operation result will complete successfully. * <p> * If any command in the script fails, none of the changes will be applied, and the result will be failed with an * error object. * * @param {String} Script - The command script * @returns {Result<undefined>} A {@link Result<undefined>} * @function Session.security#updateSecurityStore * * @example * session.security.updateSecurityStore(script).then(function() { * console.log('Security configuration updated'); * }, function(err) { * console.log('Failed to update security configuration', err); * }); */ 'updateSecurityStore', /** * Send a command script to the server to update the authentication store. The script may be produced by the * builder {@link SystemAuthenticationScriptBuilder}. * <P> * If the script is applied without error to the server, the operation result will complete successfully. * <p> * If any command in the script fails, none of the changes will be applied, and the result will be failed with an * error object. * * @param {String} Script - The command script * @returns {Result<undefined>} A {@link Result<undefined>} * @function Session.security#updateAuthenticationStore * * @example * session.security.updateAuthenticationStore(script).then(function() { * console.log('Authentication configuration updated'); * }, function(err) { * console.log('Failed to update security configuration', err); * }); */ 'updateAuthenticationStore', /** * Returns a {@link SecurityScriptBuilder} that can be used to modify the server's {@link * Session.security.SecurityConfiguration}. * * @return {SecurityScriptBuilder} A script builder * @function Session.security#securityScriptBuilder */ 'securityScriptBuilder', /** * Returns a {@link SystemAuthenticationScriptBuilder} that can be used to modify the server's {@link * Session.security.SystemAuthenticationConfiguration}. * * @return {SystemAuthenticationScriptBuilder} A script builder * @function Session.security#authenticationScriptBuilder */ 'authenticationScriptBuilder', /** * Register a handler for client authentication events. * <P> * Each handler is registered under a particular <code>handlerName</code>. For * registration to succeed, the server's security configuration must include * a matching <code><control-authentication-handler/></code> entry for the name. * Otherwise registration will fail, the handler will be closed immediately, * and an error will be reported to the session error handler. * <P> * Each control session can register a single handler for a <pre>handlerName</pre>. See * {@link AuthenticationHandler#onActive}. * <P> * It is normal for several or all of the control sessions in a control * group to set a handler for a given name. Registration will fail if a * session in a different control group has registered a handler using the * name. * <P> * For each authentication event, the server will use its configuration to * determine the handler priority order. The server can call authentication * handlers in serial or parallel. The server can stop the authentication * process as soon as it has an allow or deny response from a handler and * all higher priority handlers have abstained. * <P> * For a configured control authentication handler, the server will select a * single handler from those registered for the <code>handlerName</code>. If * no handlers are currently registered, the server will consult the next * handler. * * @param {String} handlerName - must match an entry in the server's security * configuration for registration to succeed * * @param {Array<diffusion.clients.DetailType>} requestedDetails - the session details that the server will supply, * if available * * @param {AuthenticationHandler} handler - the authentication handler to set * * @example * // Set a simple handler to handle pre-defined principals, otherwise defer to default handling * session.security.setAuthenticationHandler('before-system-handler', [], { * onAuthenticate : function(principal, credentials, details, callback) { * if (principal === 'alice' && credentials === 'hello') { * callback.allow(); * } else if (principal === 'bob') { * callback.deny(); * } else { * callback.abstain(); * } * }, * onActive : function(deregister) { }, * onClose : function() { }, * onError : function() { } * }); * * @example * // Set a handler that allocates roles & properties to certain sessions * session.security.setAuthenticationHandler('before-system-handler', [diffusion.clients.DetailType.SUMMARY], { * onAuthenticate : function(principal, credentials, details, callback) { * * if (details.summary.clientType === diffusion.clients.ClientType.IOS && * details.summary.transportType === diffusion.clients.TransportType.WEBSOCKET) { * * // Session will be authenticated with the 'WS_IOS' role, and an assigned session property * callback.allow({ * roles : ['WS_IOS'], * properties : { * PropertyName : 'PropertyValue' * } * }); * } else { * callback.abstain(); * } * }, * onActive : function(deregister) { }, * onClose : function() { }, * onError : function() { } * }); * * @function Session.security#setAuthenticationHandler */ 'setAuthenticationHandler' ]); Security.AuthenticationHandler = AuthenticationHandler; Security.SecurityScriptBuilder = SecurityScriptBuilder; Security.SystemAuthenticationScriptBuilder = SystemAuthenticationScriptBuilder; Security.SecurityConfiguration = SecurityConfiguration; Security.SystemAuthenticationConfiguration = SystemAuthenticationConfiguration; Security.Role = Role; Security.SystemPrincipal = SystemPrincipal; module.exports = Security;