3. Entitlement Modules

What’s An Entitlement Module?

Entitlement modules manage access to resources within AMPS. Given a user identity, entitlement modules determine whether that user can access a resource within AMPS and whether the user can write to the resource, read from the resource, or both.

AMPS doesn’t dictate how your module determines whether to grant access or not. Your module may look up permissions in an external resource such as a file or a database, may interpret the request directly (for example, your module could deny all write requests by usernames that contain “-TEMP”), or use any other method to determine access.

When to Implement an Entitlement Module

Implement an entitlement module when your AMPS installation needs to enforce specific permissions for individual users, and none of the modules included with AMPS meet your needs. The default modules provided by AMPS either allow or deny all permissions. Auxiliary modules are provided in the AMPS distribution that can provide more fine-grained entitlement schemes: see the User Guide for details.

Entitlement Context

AMPS manages entitlements for authenticated clients. Entitlement modules are used for a specific transport, to manage resource access for clients that connect over that transport. The same module may have different configuration settings for different transport settings. For example, one port may be enabled to publish offers to AMPS, and may manage access through one set of permissions, while a different port, and different set of permissions, may be used for subscribers to the offers.

Because the same module may be used with different parameters on different transports, AMPS allows you to save the parameters in an entitlement context.

Your module implements the amps_entitlement_create_context function to create an entitlement context. The function has this signature:

amps_entitlement_context amps_entitlement_create_context(amps_module_options options);

options An array of amps_module_options structs. The array is terminated by a struct with a NULL key.

The entitlement context is a pointer to data that your module defines. The AMPS server does not process or interpret this data. The server receives the pointer from your module when the module is initialized, and then provides the pointer back to your module for each authentication request. Notice that you cast the pointer to amps_entitlement_context before you return it, and cast the pointer back to the type that your application uses after AMPS returns the pointer to you.

Tip

AMPS doesn’t provide explicit information about the transport or message type in the entitlement call.

If you need to enforce different permissions based on transport or message type (for example, only automated systems are entitled to publish XML or connect using the UDS transport), you set those options when you declare the entitlement context and retrieve them to process the entitlement request.

AMPS passes configuration options to modules as a pointer to an array of amps_option structs. AMPS indicates the end of the array with an option that has a NULL key. Your module processes options until it reaches an option with a NULL key. If no options are specified in the configuration file, the first amps_option in the array will have a NULL key.

The following snippet shows one way to process options:

for (; options->key != NULL; ++options) {
    // process the key/value pair here
}

Your module is responsible for allocating any memory returned as part of an entitlement context. When AMPS exits, AMPS calls amps_entitlement_destroy_context with each of the entitlement contexts created. This gives your module an opportunity to do any resource management, cleanup or logging necessary before AMPS shuts down. The function has this signature:

int amps_entitlement_destroy_context(amps_entitlement_context context);
context
  • The authentication context to be destroyed.

Your module uses the context to free resources, including memory, before returning.

Managing Access to Resources

AMPS passes authentication requests to your module by calling amps_entitlement_check() or amps_entitlement_check_v2(), depending on which of these functions your module has implemented.

The amps_entitlement_check function has the following signature:

int amps_entitlement_check(amps_entitlement_context       context,
                           const char*                    user,
                           size_t                         userLength,
                           enum
                           amps_entitlement_resource_type resourceType,
                           const char*                    resource,
                           size_t                         resourceLength,
                           char**                         filter,
                           size_t*                        filterLength,
                           int                            entitlement);

The amps_entitlement_check_v2 function has the following signature:

int amps_entitlement_check_v2(amps_entitlement_context       context,
                              const char*                    user,
                              size_t                         userLength,
                              enum
                              amps_entitlement_resource_type resourceType,
                              const char*                    resource,
                              size_t                         resourceLength,
                              char**                         filter,
                              size_t*                        filterLength,
                              char**                         selectList,
                              size_t*                        selectListLength,
                              int                            entitlement);

AMPS passes the following parameters:

  • context is the pointer returned by the call to amps_entitlement_create_context() for the transport that received the request.

  • user and userLength provide the username for the entitlement request.

  • resourceType provides the type of resource requested, using the resource types defined in amps_authorization.h. AMPS can request one of the following resource types:

    Value Resource
    amps_resource_logon Client connection
    amps_resource_replication_logon Replication connection
    amps_resource_topic Topic
    amps_resource_admin Administrative functionality

Table 3.1: Entitlement Resource Types

  • resource and resourceLength provide the name of the resource requested. Notice that for logon resources, the name of the resource is empty.

  • filter and filterLength allow your module to add a filter to a topic when the entitlement request succeeds. For example, the user may only have permission to view orders with the ‘available’ attribute or orders where the ‘assignedTo’ attribute matches the user name. The filter provided must be a valid AMPS filter. As with filters on content subscriptions, AMPS parses the filter to ensure that the filter has valid syntax, but doesn’t guarantee that the filter will match the content of any particular message. For extra protection, 60East recommends using filters that will evaluate correctly on incomplete or malformed messages. In other words, a filter such as /status in ('new', 'open, 'pending', 'refused', 'cancelled') will only return messages that have a status field with one of those statuses set. A filter such as /status <> 'complete' will return messages with any status other than complete, which may include malformed messages or messages with missing status fields.

    AMPS manages the lifetime of strings returned in the filter parameter, so these strings must be allocated with the allocation function provided during module initialization.

  • selectList and selectListLength allow your module to control read access to fields on messages in the topic when the entitlement request succeeds. For example, a given user may not have permission to view the confidentialNotes field of messages in a State-of-the-World topic, even though the user may have access to the other fields. Entitlement select lists follow the same syntax as select lists in subscription options. For example, a select list of -/,+/publicField would allow a user to only see the value of the publicField field of the message.

    Notice that a select list should only be provided if the instance uses message types for which AMPS can construct a partial message.

    AMPS manages the lifetime of strings returned in the selectList parameter, so these strings must be allocated with the allocation function provided during module initialization.

  • entitlement indicates whether the request is for read access (AMPS_READ_ALLOWED), write access (AMPS_WRITE_ALLOWED), or replication access (AMPS_REPLICATION_ALLOWED).

To implement an entitlement check, your module uses the provided parameters to determine whether the user provided has the requested type of access to the resource provided. Your function returns AMPS_SUCCESS if the user is entitled to perform the operation requested on the resource requested. If the user is not entitled, the user returns AMPS_FAILURE.

Tip

For efficiency, AMPS caches the results of requests for a given resource, access type and user name. This is particularly important when developing and debugging your module: your module does not receive an entitlement request for every access to a resource. Instead, AMPS may cache the result that your module returns. Notice also that AMPS does not guarantee a particular length of time for maintaining cached results, and may discard the results and resend the request as necessary.

Resetting Cached Entitlements

AMPS provides functions that a module can use for resetting cached entitlements for a specific user or for all of the users on a specific transport.

Tip

When AMPS resets entitlements for a user, AMPS disconnects that user.

For example, use the following function to reset information for a specific user. Provide a pointer to a null-terminated (C-style) string for the pClientAuthId_ parameter. The pTransportName_ parameter is either the name of the transport for which to reset the permissions, or NULL (that is, 0) to reset that user for all transports in the instance.

int amps_reset_entitlement_for_authid(const char* pTransportName_,
                                      amps_authid pClientAuthId_);

Notice that this function must not be called from within a call to amps_entitlement_check that uses the transport to reset.

The AMPS API provides other, related functions for resetting entitlements. See amps_api.h for details.