Viewing: Advanced Domain Features > Row-Level Security

The Domain Security File

The security file defines permissions to control access to Domain data on the basis of user names and roles existing in the server. When creating or running a report based on a Domain, the user name and roles are checked against the permissions in the security file. Permissions can be set separately on the data’s columns and rows.

Security on columns is defined by permissions on the sets and items of the Domain, corresponding to columns in the data source. For example, only certain users might be able to see sensitive employee information such as a Social Security Number. Security on rows is defined by permissions on the data values, for example a manager might only be allowed to see the salary column of employees whose manager field equals the manager’s employee number.

The IDs of tables, columns, sets and items that appear in the design are referenced by the security file. In Domains, columns display the items in the Domain; rows display the values of each item. Column security is defined on itemGroupId and itemId; row security is defined on resourceId.

A user can only see results where he has both column- and row-level access. For instance, in a certain Domain, user David has access to columns A-F and rows 1-6. Tomas has access to columns B-C and rows 1-3. Anita has access to columns C-E and rows 2-5. When the users run reports from the Domain, they get different results. David sees data in cells where columns A-F and rows 1-6 intersect. Tomas sees data only where columns B-C and rows 1-3 intersect. Anita sees data only where columns C-E and rows 2-5 intersect.

 

 

Item A

Item B

Item C

Item D

Item E

Item F

1

David

David

Tomas

David

Tomas

David

David

David

2

David

David

Tomas

David

Tomas

Anita

David

David

David

3

David

David

Tomas

David

Tomas

Anita

David

Anita

David

Anita

David

4

David

David

David

Anita

David

Anita

David

Anita

David

5

David

David

David

Anita

David

Anita

David

Anita

David

 

6

David

David

David

David

David

David

For a given query on the data source, the security definition finds the access grants and determines his access rights, determined first for item groups and items, then for resources. When the query is passed to the data source and the report is run, the grants are applied as filters on the report’s columns and rows. Security that is defined on the physical layer applies to all content in the presentation layer. Security that is defined on a join applies only to the presentation layer content that is specific to the join.

When a user is designing a report in the Ad Hoc Editor, he sees only the columns to which he has access. When the report runs, portions to which the user has no access are blank.

Access grants take a principalExpression that evaluates the principal in authentication objects created in the Acegi security framework (http://www.jasperforge.org). The standard expression is

<principalExpression>authentication.getPrincipal().getRoles().any{ it.getRoleName() in ['ANY_SUPPORTED_ROLE'] }

</principalExpression>

The expression gets the current authentication object and determines the access privileges of the principal in the object. Then, from the server, it gets the user and roles associated with the object. Finally, it evaluates the roles for the specified role. The access grants are applied to the role.

The expression evaluates to

<principalExpression>authentication.principal.roles.roleName in ('ANY_SUPPORTED_ROLE')

</principalExpression>

While the standard principal expression tests for a given role, an expression can test for any object in the principal. For example, this expression tests for attribute A:

<principalExpression>authentication.getPrincipal().getAttributes().any{ it.getAttributeA() in ['ANY_SUPPORTED_ROLE'] }

</principalExpression>

The scripting language for principalExpression is Groovy.

 

For more information about Groovy, go to http://groovy.codehaus.org.

All access grants for a Domain are defined in a single security file that is attached to the Domain as a resource, as described in section Security and Locale Information for a Domain. The default access is granted.

When creating a security file, be sure to use the IDs of items and groups as they are defined in the Domain design file exported from the Domain Designer. For more information, see section Working With a Design File.

If you modify the Domain, you should also export the design file and update the security file with any IDs that have changed. Update the security file using the Change function on the Edit Domain page of the Domain Designer.

 

Changing a Security File in the Domain Designer

A typical security file has the following structure:

 

<securityDefinition xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema"

version="1.0" itemGroupDefaultAccess="granted">

<resourceAccessGrants> <!-- Begin row-level security -->

<resourceAccessGrantList id="expense_join_resource_access_grant" label="aLabel"

 resourceId="expense_join">

<resourceAccessGrants>

<resourceAccessGrant id="expense_join_ROLE_SUPERMART_MANAGER_store_row_grant">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }

</principalExpression>

<filterExpression>s.store_country in ('USA') and s.store_state in ('CA')

</filterExpression>

</resourceAccessGrant>

...

</resourceAccessGrants>

</resourceAccessGrantList>

...

</resourceAccessGrants>

 

<itemGroupAccessGrants> <!-- Begin column-level security -->

<itemGroupAccessGrantList id="expense_join_item_group_access_grant_group"

label="aLabel" itemGroupId="expense_join" defaultAccess="denied">

<itemGroupAccessGrants>

<itemGroupAccessGrant id="expense_join_super_user_item_group_grant"

access="granted">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_ADMINISTRATOR'] }

</principalExpression>

</itemGroupAccessGrant>

...

</itemGroupAccessGrants>

</itemGroupAccessGrantList>

...

</itemGroupAccessGrants>

</securityDefinition>

Row-Level Security

Row-level security is specified in resourceAccessGrants. For each dataset from which data is returned by a query in the design file, a resourceAccessGrantList specifies the rows to which a user has access. Each grant is defined in a resourceAccessGrant that contains a principalExpression and a filterExpression.

A resourceAccessGrant must be defined for a joined resource if any query in the security definition has at least one item from the resource, even if that query does not include the related dataset.

Row-level security applies whenever access to a secured resource is requested, even if the request is indirect. For instance, a column in the Region table might be joined to a column in the Sales table. User Tomas has access to Region but not Sales. Tomas’s report uses columns from Region but he cannot see them because he does not have access to Sales.

Row-level security is defined as follows:

 

<resourceAccessGrants> <!-- Begin row-level security -->

<resourceAccessGrantList id="expense_join_resource_access_grant" label="aLabel"

 resourceId="expense_join">

<resourceAccessGrants>

<resourceAccessGrant id="expense_join_ROLE_SUPERMART_MANAGER_store_row_grant">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<filterExpression>s.store_country in ('USA') and s.store_state in ('CA')

</filterExpression>

</resourceAccessGrant>

<resourceAccessGrant id="account_ROLE_SUPERMART_MANAGER_account_row_grant"

 orMultipleExpressions="true">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<filterExpression>s.store_number == 0</filterExpression>

</resourceAccessGrant>

<resourceAccessGrant id="account_ROLE_SUPERMART_MANAGER_account_row_grant2"

 orMultipleExpressions="true">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName()

in ['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<filterExpression>s.store_number == 24</filterExpression>

</resourceAccessGrant>

</resourceAccessGrants>

</resourceAccessGrantList>

<resourceAccessGrantList id="account_resource_access_grant" label="aLabel"

 resourceId="account">

<resourceAccessGrants>

<resourceAccessGrant id="account_resource_super_user_row_grant">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_ADMINISTRATOR'] }</principalExpression>

</resourceAccessGrant>

<resourceAccessGrant id="account_ROLE_SUPERMART_MANAGER_row_grant">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<filterExpression>account_type == 'Expense'</filterExpression>

</resourceAccessGrant>

</resourceAccessGrants>

</resourceAccessGrantList>

</resourceAccessGrants>

Elements of resourceAccessGrants are:

   resourceAccessGrantList. List of grants for one dataset in the Domain.

    resourceAccessGrant. Grant in the dataset for a specific case, such as a user or role.

principalExpression. Evaluation of the authentication object and user to determine the role to be granted access.

filterExpression. Filter on the dataset; determines the rows to which access is granted. Filters are applied to resource IDs. See the section The DomEL Syntax for examples of valid filter expressions. For an alternative to writing filter expressions in Groovy, see the testProfileAttribute function in Operators and Functions.

Column-Level Security

Column-level security is specified in itemGroupAccessGrants. An itemGroupAccessGrantList defines default access to one item group. Within the group, access is granted by user role in itemGroupAccessGrants. Access to items within an item group can be specified by itemAccessGrants.

Column-level security passes from parent object to child object unless specified otherwise:

   If access is unspecified for an object, the access of the parent object applies. If the unspecified object is an item in an item group, the item group’s access applies.

   If the unspecified object is an item in an item group that is nested in another item group, the access of the nearest parent item group applies to the item.

If the nearest parent group’s access is also unspecified, that group takes its access from its parent group and passes it to the item. In this case (specified item group > unspecified item group > unspecified item), access for the item cannot be specified in an item-level grant.

   If access is specified for an item group but there is no item group principal expression matching the current user, the user has the item group’s default access, not the item group’s specified access.

If a matching item group principal expression does exist, the user’s access to items depends on access specifications, if there are any. Access to other items depends on the item group’s specified access.

If multiple item group principal expressions match the user (such as one expression for the user and one for his role), their access grants are combined, or ANDed, in a simple series. As a result, one denied statement overrides multiple granted statements.

Column-level security is defined as follows:

 

<itemGroupAccessGrants> <!-- Begin column-level security -->

<itemGroupAccessGrantList id="expense_join_item_group_access_grant_group" label="aLabel"

itemGroupId="expense_join" defaultAccess="denied">

<itemGroupAccessGrants>

<itemGroupAccessGrant id="expense_join_super_user_item_group_grant" access="granted">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_ADMINISTRATOR'] }</principalExpression>

</itemGroupAccessGrant>

<itemGroupAccessGrant id="ROLE_SUPERMART_MANAGER_item_group_access_grant"

access="granted">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<itemAccessGrantList id="expense_join_ROLE_SUPERMART_MANAGER_item_grant"

 defaultAccess="denied">

<itemAccessGrants>

<itemAccessGrant id="itemAccessGrant1" itemId="ej_expense_fact_exp_date"

 access="granted" />

</itemAccessGrants>

</itemAccessGrantList>

</itemGroupAccessGrant>

</itemGroupAccessGrants>

</itemGroupAccessGrantList>

 

<itemGroupAccessGrantList id="expense_join_store_item_group_access_grant_group"

label="aLabel" itemGroupId="expense_join_store" defaultAccess="denied">

<itemGroupAccessGrants>

<itemGroupAccessGrant id="expense_join_store_super_user_item_group_grant"

access="granted">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_ADMINISTRATOR'] }</principalExpression>

</itemGroupAccessGrant>

<itemGroupAccessGrant id="ROLE_SUPERMART_MANAGER_store_item_group_access_grant"

access="granted">

<principalExpression>

authentication.getPrincipal().getRoles().any{ it.getRoleName() in

['ROLE_SUPERMART_MANAGER'] }</principalExpression>

<itemAccessGrantList id="expense_join_ROLE_SUPERMART_MANAGER_store_item_grant"

 defaultAccess="denied">

<itemAccessGrants>

<itemAccessGrant id="itemAccessGrant3" itemId="ej_store_store_type"

 access="granted" />

<itemAccessGrant id="itemAccessGrant4" itemId="ej_store_region_id"

 access="granted" />

<itemAccessGrant id="itemAccessGrant5" itemId="ej_store_store_name"

 access="granted" />

<itemAccessGrant id="itemAccessGrant6" itemId="ej_store_store_number"

 access="granted" />

<itemAccessGrant id="itemAccessGrant7" itemId="ej_expense_fact_exp_date"

 access="granted" />

<itemAccessGrant id="itemAccessGrant8" itemId="ej_expense_fact_amount"

 access="granted" />

</itemAccessGrants>

</itemAccessGrantList>

</itemGroupAccessGrant>

</itemGroupAccessGrants>

</itemGroupAccessGrantList>

</itemGroupAccessGrants>

Elements of itemGroupAccessGrants are:

   itemGroupAccessGrantList. List of access grants to one item group. Specifies default access to the item group and all items in the group. If you want to restrict access to items outside of any group or set, create an itemGroupAccessGrantList for them where the id of the group is "".

    itemGroupAccessGrant. Specifies access to the item group for one user role.

principalExpression. Evaluation of the authentication object and user to determine the role to be granted or denied access.

itemAccessGrantList. List of access grants to items in the item group. Specifies default access to the items. Overrides default in itemGroupAccessGrantList.

itemAccessGrant. Specifies access to one item.

In the above example, the progression of column access grants is:

   Deny access to everyone.

   For each item group:

    Grant group access to administrator roles.

    Grant group access to additional roles.

    For each additional role, deny access to specific items or, alternatively, deny access to all group items, then grant access to specific items.

Access is denied to everyone initially. Otherwise, all users would have complete access. Next, access to each item group is granted for administrator roles.

Next, access is defined for the SuperMart manager role. First, access is granted to each item group even though the access may be limited eventually. If access is not granted at the group level, the SuperMart manager has no access at all. Then, access to all items in the group is denied, followed by grants to specific items.

An alternative way to restrict access is to simply deny it on specific items. However, this method is not as secure as denying access to all items then granting access to some. The latter requires the programmer to specifically identify each item to which the role has access, which is more secure.

By default, all grants for a given role are ANDed. The ANDed series can be modified by an OR expression (orMultipleExpressions="true"). For instance, the following grants are implemented as A and B and C:

<resourceAccessGrant id="A">

<resourceAccessGrant id="B">

<resourceAccessGrant id="C">;

while these grants are implemented as (A or B) and C:

<resourceAccessGrant id="A">

<resourceAccessGrant id="B" orMultipleExpressions="true">

<resourceAccessGrant id="C">

The OR expression can be applied in grants for items and item groups as well as resources.