Each REST API operation is authenticated to check if the user has the required privileges.

There is a plugin architecture to allow different entitlement mechanisms to be used. A new entitlements checker implementation can be supplied by implementing

User Entitlements

User entitlements can be set globally with the property:,itil


RBAC Entitlements

Each REST API operation (to list/view items, or to perform changes) is authenticated to check if the user has the required privileges.

There is a plugin architecture to allow different entitlement mechanisms to be used. One mechanism available is io.cloudsoft.amp.entitlements.rbac.PerRoleEntitlementManager. This allows plugins for the various decision points.

Note: these package names may change if the code moves to org.apache.brooklyn. Configuration

This reads from brooklyn.cfg, such as:

The userToRole refers to a class of type io.cloudsoft.amp.entitlements.rbac.RoleResolver, available in a bundle whose symbolic name is com.acme.amp.rbac, which maps from a user to the role(s) for that user. If a user is in multiple roles, then the user has permission if any of the roles grant that permission.

The roleCacheExpiryDuration is the duration that the roles of a user will be cached for. Note that an extreme (!) way to flush the cache is to “reload properties”, which will replace this EntitlementManager with a new instance.

The perRole has an entry per role name. This value can be to a pre-defined build-in role (i.e. “root”, “readonly” and “minimal”). Alternatively, it can point to a custom class. RoleResolver.

In addition to the perRole entries, it’s possible to define mapping between groups defined only as part of the ExplicitUsersAndRolesSecurityProvider.ROLES_FOR_USER keys or only from the groups from LDAP. See example

An instance of the class will be instantiated reflectively. The constructor should have a signature that is one of:

    (ManagementContext mgmt, AMPProperties properties)
    (ManagementContext mgmt)
    (AMPProperties properties)

If the class also implements {@link ManagementContextInjectable}, then the management context will be injected immediately after construction.

Custom EntitlementManager

The RBAC configuration allows one to plugin a custom entitlement manager to be associated with a given role, to meet your exact needs.

The EntitlementManager interface has a single method: isEntitled. This is passed details of the what is being done, and to what, allowing a boolean to be returned to indicate if it is permitted.


The class io.cloudsoft.amp.entitlements.rbac.LdapGroupsResolver implements RoleResolver and looks for the user roles inside the request EntitlementContext

Using or as Security Provider and the proper configuration will put on the EntitlementContext the user LDAP groups mapped with the prefix passed to the config key

DomainLocalSecurityProvider example

DomainLocalSecurityProvider extends the functionality of the LdapSecurityProvider adding also the local definition of users and grops using alternatively ExplicitUsersAndRolesSecurityProvider when the LDAP authentication fails.

This example will use a hybrid set of user and entitlements, two users defined in the config file and their groups, and also the mapping for the groups for the LDAP user

# Local user names,readonlyPlusLogs
# Plain text password

# user "admin" group

# user "readonlyPlusLogs" groups,log_viewer_group

# UI module for replace default browser login

# Security provider

# LDAP configuration. See LDAP conf<server>:389/

# AMP will ignore LDAP groups not mapped with the next key

# Entitlement manager

# Group Resolver

# Mapping for the LDAP groups amp_administrators_group, log_viewer_group and readonly_group

# Mapping for the AMP groups amp_administrators_group, readonly_group and log_viewer_group

# Valid mapping for groups defined in LDAP or in this file

This example user the ...perRole entry to be mapped with the logViewer entitlement for user on the LDAP group named “log_viewer_group” but also to the readonlyPlusLogs group defined in the same file.

LDAP Entitlements

AMP supports LDAP integration for entitlements - i.e. the entitlements rules are stored in LDAP. To use this, you must set in your

# requires LDAP used for authorization
# and set the entitlements to be this implementation (or a subclass, if necessary)

In the LDAP schema, this entitlements scheme requires a new objectClass, which in this guide we will call acmePermission, with the following attributes (all marked optional):

  • entityTagRegexesForNavigating: means you can navigate to entities with any tag matching any regex (multi-valued LDAP attribute)
  • entityTagRegexesForReading: means you can see sensors+config on entities with any tag matching any regex (multi-valued LDAP attribute)
  • entityTagRegexesForWriting: means you can invoke effectors on entities with any tag matching any regex (multi-valued LDAP attribute)
  • deployAllowed: means you are allowed to deploy new applications (boolean / present or absent)
  • serverInfoAllowed: means you are allowed to see AMP information (boolean / present or absent)
  • root: means you are root, having all the permissions above and all others (boolean / present or absent)

The DIT will contain:

  • an OU (groups) containing Posix Groups, where each group defines
    • zero or more user members
    • an acmePermission object, defining permissions for all members of the group
  • an OU (users) containing User Accounts, where each user defines
    • the password attribute
    • an acmePermission object, defining specific permissions for that user (in addition to all permissions from all groups)

This structure allows to have single User Account with (1) permissions defined specific to that user, and (2) permissions defined on groups of which he/she is a member. As is often recommended for entitlements, these are purely additive: a user will be entitled to access anything which is entitled by any acmePermission object on the user or any of his/her groups.

An example for (1) is:

  • user1 has entityTagRegexesForNavigating: acme.tenant.entity:${user} attribute

while an example of (2) is:

  • administrators group has 2 values for the entityTagRegexesForNavigating attribute: acme.tenant.entity.master and acme.tenant.entity:${user}
  • user2 is memeber of administrators group so user2 inherits the acme.tenant.entity.master to see the AMP blueprint and acme.tenant.entity:${user} to see his own child AMP.

Please see the LDAP command reference section for instructions for configuring LDAP with the acmePermission schema.

Use Cases

Using the LDAP structure described above with the new AMP feature to manage entitlements, it is possible to cover the following scenarios of interest:

Entitlements for master AMP and tenants/children AMP

In order to enforce entitlement on the master AMP, we need to add tags to the entities so that when we create Tenant-Foo AMP at master, we tag Tenant (AMPNode) and Service (AMPMirror) entities as acme.tenant.entity:${user} (where ${user} is replaced with the tenant name). Also we add tag acme.tenant.entity.master to the master blueprint so that all users can navigate through it (to access their tenant) and so that controllers can invoke effectors there. These tags are done by the AMP Master blueprint (no manual steps needed).

In LDAP, we define the following permissions:

  • tenant group:
    • entityTagRegexesForNavigating: acme.tenant.master, acme.tenant.entity:${user} (where ${user} is literal, the substitution done by the permissions engine)
    • entityTagRegexesForReading: acme.tenant.entity:${user}
    • entityTagRegexesForWriting: acme.tenant.entity:${user}
  • admin group:
    • entityTagRegexesFor...: .* (all permissions)
    • deployAllowed
    • serverInfoAllowed
    • root (with this permission the others are redundant)
  • controller group (WIP):
    • entityTagRegexesFor...: acme.tenant.master, acme.tenant.entity:.* (controllers given all rights to access master root node and all tenant entities at master, but not webapps)

Then in AMP, when a tenant logs in to the master, it will enforce:

  • authentication: we look up user/password in ldap
  • entitlements on the tenant AMP:
    • we fetch the acmePermission attributes attached to the user and for those groups of which he/she is a member
    • we evaluate those permissions to determine whether they are allowed to see the tenant using the tags associated to the tenant entity.
    • (we store these permissions in a cache which is invalidated after 15m or whatever refresh time we require)

A tenant can manage everything tagged with acme.tenant.entity:${USER}

Entitlements check on login at Tenant AMP instances, based on identity of which AMP server

This is deferred to the second iteration. Two options are:

  • Updating LDAP on Tenant AMP creation and installing this at the tenant AMP
  • A signed secret that the master AMP returns to the user to login to the tenant AMP that she claims to own

In the first iteration access to Tenant AMPs is driven by credentials stored in the Master AMP.

  • Users, credentials, and permissions are stored in one well-known external system
  • Framework for defining entitlements which is already powerful, and easily extensible

The entitlements for the entity/sensors/effectors on the tenant AMP will be addressed on the second iteration.

LDAP command reference

Currently, we added to the ldap schema a acmePermission objectClass with 6 attributes:


Starting from a new openldap 2.4 instance, it is possible to add the acmePermission objectClass by issuing the following commands:

ldapadd -Q -Y EXTERNAL -H ldapi:/// -f acme.ldif


This ldif file has been created starting from the following acme.schema placed in (/etc/ldap/schema/acme.schema)

attributetype (
	NAME 'root'
	DESC 'regex to match entity tag that allows browsing entities'
	EQUALITY booleanMatch

attributetype (
	NAME 'deployAllowed'
	DESC 'deployAllowed'
	EQUALITY booleanMatch

attributetype (
	NAME 'serverInfoAllowed'
	DESC 'serverInfoAllowed'
	EQUALITY booleanMatch

attributetype (
	NAME 'entityTagRegexesForNavigating'
	DESC 'regex to match entity tag that allows browsing entities'
	EQUALITY caseExactMatch
	SUBSTR caseIgnoreSubstringsMatch

attributetype (
	NAME 'entityTagRegexesForReading'
	DESC 'regex to match entity tag that allows reading entities'
	EQUALITY caseExactMatch
	SUBSTR caseIgnoreSubstringsMatch

attributetype (
	NAME 'entityTagRegexesForWriting'
	DESC 'regex to match entity tag that allows writing entities'
	EQUALITY caseExactMatch
	SUBSTR caseIgnoreSubstringsMatch

objectclass ( NAME 'acmePermission'
    DESC 'permissions for Acme'
    SUP top
	MAY ( root $ deployAllowed $ serverInfoAllowed $ entityTagRegexesForNavigating $
          entityTagRegexesForReading $ entityTagRegexesForWriting ) )

by using slaptest utility.

cd /tmp/ldap
cat > schema_convert.conf <<EOT
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/collective.schema
include /etc/ldap/schema/corba.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/duaconf.schema
include /etc/ldap/schema/dyngroup.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/java.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/openldap.schema
include /etc/ldap/schema/ppolicy.schema
include /etc/ldap/schema/ldapns.schema
include /etc/ldap/schema/pmi.schema
include /etc/ldap/schema/acme.schema
mkdir ldif_output
slapd -f schema_convert.conf -F . 
slapcat -f schema_convert.conf -F ldif_output -n 0 | grep acme,cn=schema
# get the output
slapcat -f schema_convert.conf -F ldif_output -n0 -H \
ldap:///<output> -l cn=acme.ldif

# Edit cn=acme.ldif to arrive at the following attributes:

dn: cn=acme,cn=schema,cn=config
cn: acme
Also remove the following lines from the bottom:

structuralObjectClass: olcSchemaConfig
entryUUID: 52109a02-66ab-1030-8be2-bbf166230478
creatorsName: cn=config
createTimestamp: 20110829165435Z
entryCSN: 20110829165435.935248Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20110829165435Z

and finally

sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=brooklyn.ldif