diffusion
Version:
Diffusion JavaScript client
718 lines (672 loc) • 29.3 kB
JavaScript
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;