# Content Access Control

* [**Content-level Permissions**](#content-level-restrictions-acls-for-kb-articles) (ACLs per Knowledge Article)
* [**Content Access Controls via APIs**](https://docs.aisera.com/aisera-platform/adding-data-to-your-tenant/content-access-control/content-access-control-via-apis) (especially for ServiceNow and Confluence)

## Content-level Restrictions (ACLs for KB Articles)

You can apply Access Control to content in two different ways.

1. **Knowledge Base Article metadata-based Access Control**
   1. At a high level, Knowledge Base Articles can contain metadata about who can view the KBA. Metadata can also include information like country, region, and roles, depending on your knowledge base system, and the tools used to create the articles. During data ingestion, the Aisera Gen AI platform also Ingests this metadata.
   2. You can include similar information about each user when you upload and ingest User Profile data.
   3. During data ingestion, the Aisera Gen AI platform extracts the metadata tags and user profile property values and saves them separately as Access Attributes.
   4. The Aisera platform uses this information to apply a filter before sending a fulfillment answer. Once the content is found by fulfillment engines like ICM/RAG/Neural Search, the Aisera platform checks to see if that content is restricted for the bot user making the request.\
      \
      If the content is not restricted from this user, then the user is served the content. **If the content has multiple access attributes, then the user profile should be unrestricted for all of them**. \
      \
      For example, if a KB Article requires the user to be in a specific security `group` for `region` `North America` the two access attribute for this article are `group=abc` and `region=NA` and the user should not be restricted from either of these attributes if you want them to view the article.
   5. Sometimes a user's profile does not have the required metadata, but during the user session such information is passed in. The Aisera platform can use such dynamically passed information as session variables. These [sessionVars](https://docs.aisera.com/aisera-platform/adding-data-to-your-tenant/content-access-control#passing-access-attributes-in-sessionvar) are used to pass the dynamic information.
2. [**Content Access Control via APIs**](https://docs.aisera.com/aisera-platform/adding-data-to-your-tenant/content-access-control/content-access-control-via-apis)

Before the application/bot serves content to a user, the Aisera platform can make a call to an external data system like Confluence/Jira/ServiceNow. The third-party API sends the Aisera platform acknowledgement that the user has access to content that the Aisera software is about to serve to the user. Data sources like Confluence only use the Content Access Control via API method. See the link above for step-by-step instructions.

### Activate Access Management for Content Control <a href="#activate-feature" id="activate-feature"></a>

The Access Management feature is disabled by default. Enable Access Management by selecting `Settings` > `Configuration` > `Access Management`in the Aisera Admin UI.

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2Fo5eLFWw2GO3dI6ZiRVd4%2Fac1.png?alt=media&#x26;token=364be14c-1456-4b6e-8b23-02620e9b205a" alt=""><figcaption><p>Activate Access Control</p></figcaption></figure>

| Enable Access Management              | This tenant level flag enables the content access control                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| User should match all attributes      | <p>This flag is true by default. With default we match all access attributes. Meaning if document has attribute country and department then user should match both. This is AND on different access attributes.</p><p>But in some cases like Sharepoint where document might have restriction based on Sharepoint Group (site group) and/or security group (AD group). In this case user can view the document if he/she is part of one of the site group OR ad group. So it's OR if this flag is not selected.</p> |
| Access policy for optional attributes | Optional attributes are those which are marked not required. Service will only use those attributes if this policy is defined.                                                                                                                                                                                                                                                                                                                                                                                      |

### Access Attributes <a href="#access-attributes" id="access-attributes"></a>

You apply restriction to content using Access Attributes. These are properties or tags within a KB Article that define who can view the article.&#x20;

Specify which article tags have a value for an access attribute using the **Ingested Tag Format.**

Configure the User Profile property for each tag in the user **Profile Field**.&#x20;

For example, to filter articles by country, configure a `country` access attribute with:

* add a tag to your KB articles that includes a country value in **Ingested Tag Format**
* add a User profile property that specifies the country of the user in a **Profile Field.**

The following access attributes are included in the Aisera application by default:

* `roles`
* `country`
* `company`
* `region`
* `groups`
* `language`

You can extend this list by creating a new access attribute.&#x20;

#### To create a new Access Attribute:

1. Navigate to **Settings > Access Control**.

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FTOayIoQNNPytHknWrEQ5%2Fac2.png?alt=media&#x26;token=ec43985f-cf7f-4e69-9798-2eb3704b35aa" alt=""><figcaption><p>Access Control Window</p></figcaption></figure>

2. Choose **+ New Access Attribute**.

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FppCURKBpV0X18J4YfabI%2Faa7.png?alt=media&#x26;token=16068d0b-a96d-4850-b082-76d36690dc7a" alt=""><figcaption><p>New Access Attribute Window</p></figcaption></figure>

3. Enter the **Name** of your new Access Attribute.
4. Check the **Enabled** box, if you want it to start working immediately.
5. Click **OK**.

You can create many Customer attributes for a single tenant,  such as `azureId`, `siteGroups`, `securityGroups`, `product`, `subProduct`,  or`segmentId.`

#### Access Attribute Properties <a href="#access-attribute-properties" id="access-attribute-properties"></a>

<div align="left"><figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2Fgvufefv3WmNAmoBvNIaK%2Fac3.png?alt=media&#x26;token=73d3c06f-98d4-453c-8da0-248b5a7152de" alt="" width="563"><figcaption><p>Edit Access Attributes for KB Articles</p></figcaption></figure></div>

| **Property**        | **Purpose**                                                                                                                                                                                                                                                   |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name                | Name of the attribute.                                                                                                                                                                                                                                        |
| Enabled             | <p>Attributes are disabled by default except  the <code>roles</code> attribute.</p><p>You can only use enabled attributes to apply the access policy.</p><p>Even algorithm will only extract enabled attributes from user profile and knowledge articles.</p> |
| Required            | <p>If <code>true,</code> the attribute will be used to determine whether the user can view the content.</p><p>If <code>false,</code> then an optional filter can be applied.</p>                                                                              |
| Multiple Values     | Allows you to add multiple values for an attribute for either a KBA or a User. Such as if a KB Article is supported in multiple countries, or a user is a member of multiple user groups                                                                      |
| Profile Field       | This field will help us extract value of an attribute for a user. You will have to select a property from user profile data model. For example to get country of a user we can use `workInfo.location.address.country`.                                       |
| Ingested Tag Format | The Aisera platform extracts the value of an attribute from content like a KBA or Service Catalog is via tags. Use this property to define which tag on content should be used for the access attribute.                                                      |

### How to Setup Permission Ingestion <a href="#how-to-setup-permissions-ingestion" id="how-to-setup-permissions-ingestion"></a>

To enable the file permissions, as previously described, you must define two fields in the **Knowledge Article Fields** section. These fields will be integral to the process of managing and integrating permissions within the user profiles, ensuring that the system can effectively store and utilize the necessary information for access control.

In a SharePoint KB Datasource press the **new Field Mapping** button and add the 2 following mappings

1. Field **TagKey** and SharePoint Field **keys**
2. Field **TagValue** and SharePoint Field **values**

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FMt0CNsaBJKFd5h3nMygy%2Facg.png?alt=media&#x26;token=873c49bf-e774-444f-b2f1-977feddd1c76" alt=""><figcaption><p>SharePoint TagKey and TagValue</p></figcaption></figure>

### How to add custom TagKey and TagValue <a href="#how-to-add-custom-tagkey-and-tagvalue" id="how-to-add-custom-tagkey-and-tagvalue"></a>

To incorporate additional custom **TagKey/TagValue** pairs, you have the option to define a JavaScript function within the configuration, specifically in the **custom script** input text box.&#x20;

The JavaScript snippet below allows you to add new pairs, such as **country** TagKey with a **Brazil** TagValue. This new pair will become a distinct element within the JSON structure under the tags array, as **global:country=Brazil** . This flexibility allows for the dynamic expansion of custom tagging and metadata associated with the data in the JSON representation.

```javascript
function transform(jsonObject) {
    var JSONParser = Java.type('org.json.simple.parser.JSONParser');
    var JSONArray = Java.type('org.json.simple.JSONArray');
    var JSONObject = Java.type('org.json.simple.JSONObject');
    var parser = new JSONParser();
    var keysList = parser.parse(jsonObject.keys);
    keysList.add("country");
    jsonObject.keys = keysList;
    var parser = new JSONParser();
    var valuesList = parser.parse(jsonObject.values);
    valuesList.add("Brazil");
    jsonObject.values = valuesList;
    return jsonObject;
} 
```

#### Ingesting Knowledge Base Article Metadata <a href="#ingesting-kb-metadata" id="ingesting-kb-metadata"></a>

Depending on your integrated knowledge base system, the metadata for the knowledge base articles can be in the form of a tag, a custom property, or defined at the folder level. Most of the time it varies from system to system.&#x20;

Before you create Access Attributes, identify the attributes that are used as metadata for the knowledge base articles in your system.

The identified attributes must be ingested as tags.&#x20;

Here are some examples:

1. Each of the Knowledge Base Articles ingested with a Data Source job have the same value for every access attribute, such as `country`. If this is the case with your articles, you can hardcode the tag value as shown below:

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FJllhU2YUEFVy8OHtPwRM%2Fac4b.png?alt=media&#x26;token=972bba54-6b7e-4d44-9d1c-35a67ba4601a" alt=""><figcaption><p>Hardcode a Tag</p></figcaption></figure>

2. The metadata for each Knowledge Base Article is derived from a folder or directory. For instance, if your company knowledge base articles in SharePoint are organized in folders or directories by country. And each user only has access to the knowledge base articles for the country they are in.
   1. The country can be extracted like this via a Custom Script during the Data Source ingestion job:

```javascript
function transform(jsonObject) {
	var JSONObject = Java.type('org.json.simple.JSONObject');
	var fileDir = jsonObject.FileRef;
	var country = "";
	if (fileDir) {
		if (fileDir.contains('SitePages/055')) {
			country = 'india';
			includeFile = true;
		} else if (fileDir.contains('SitePages/221')) {
			country = 'australia,new zealand';
			includeFile = true;
		}
	}
	if (country != "") {
		jsonObject.country = country;
	}
	return jsonObject;
}
```

&#x20;     b. Field mapping to ingest `country` metadata as a tag:

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FIqgO5U4AfMGKjRo6Zrfy%2Fac4c.png?alt=media&#x26;token=78da81e0-347c-42ca-a34b-a8f650799a28" alt=""><figcaption><p>Field Map</p></figcaption></figure>

3. Each knowledge base article has this metadata available as a custom property.
   1. Ingested data already has a property that you can use.
   2. Map the field.

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FUmg7hI3uGvSsFPzED2UM%2Fac4d.png?alt=media&#x26;token=aceca78f-250c-4a1a-9c8f-0ba87b052557" alt=""><figcaption><p>Field Map</p></figcaption></figure>

4. Multiple properties
   1. Using a `Custom Script` during Data Source ingestion, you can build two lists to create **key:value pairs**.  One contains a list of **Keys** and another contains a list of **Values**. \
      \
      The order of the **key** and the associated **value** should match in both lists.

```
function transform(jsonObject) {
	var keys = [];
	var values = [];
	if (jsonObject && jsonObject.Product__c) {
		keys.push('Product');
		values.push(jsonObject.Product__c);
	}
	if (jsonObject && jsonObject.Product_Line__c) {
		keys.push('ProductLine');
		values.push(jsonObject.Product_Line__c);
	}
	if (jsonObject && jsonObject.Sub_Product__c) {
		keys.push('SubProduct');
		values.push(jsonObject.Sub_Product__c);
	}
	if (keys.length > 0) {
		jsonObject.keys = keys;
		jsonObject.values = values;
	}
	return jsonObject;
}
```

4. Field Mapping

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FG9WZd2zRU8MRFhaD8C0F%2Fac4e.png?alt=media&#x26;token=3aaf8fe1-578d-4777-84f3-38662ab8b92f" alt=""><figcaption><p>Mapping Fields</p></figcaption></figure>

4. SharePoint Permission
   1. Many of our customers have knowledge articles in Sharepoint and they are using Sharepoint’s in-built access control mechanism. Via this mechanism document can be restricted based on Sharepoint `Site Group`, List of Users (using user’s AzureId) and Azure AD `Security Group`. More information can be found in **Group access information (ACL) for Sharepoint Knowledge Base Articles**.

### Access Attribute extraction <a href="#access-attribute-extraction" id="access-attribute-extraction"></a>

The Aisera Gen AI platform includes an algorithm to extract attribute values for knowledge and users. To extract attributes, troubleshoot, or debug access attributes, see your implementation team. This information is covered in their Implementation Guide.

### User messaging <a href="#user-messaging" id="user-messaging"></a>

When any content gets filtered out from being served to the user because of access policy, then user will be informed via a message that some of the content was removed because of the access policy.

**IMPORTANT:** This message is not supported when content is served via the RAG and NS fulfillment engines.

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FAqTJp5Ba2GO4hgr7GgJY%2Facj.png?alt=media&#x26;token=155474eb-4e59-4828-8469-6240ce52d142" alt=""><figcaption><p>Access Denial Message</p></figcaption></figure>

The message is configurable. To change the message please go to the app. Select the `Conversation Messages`. Look for key `access_policy_restricted_content_preamble`.&#x20;

#### Request Resolution Type <a href="#request-resolution-type" id="request-resolution-type"></a>

The request will be marked `Correct Answer` when we have identified an intent but intent was filtered out because of access policy. The bot understood what user was inquiring about, but it could not serve because of customer’s access policy.

If we could not identify any intent, but we found something via search then that request will be stored as `Not Understood`.

### Optional Filters <a href="#optional-filter" id="optional-filter"></a>

You can apply an optional filter to an Access Attribute that is active and is specified as not required.&#x20;

For example, you can apply a filter based on language.&#x20;

If a user asks a question in German, and multiple documents are available on the requested topic with different languages, then you want to provide an answer from the Knowledge Base Article that is written in German. But what happens if you knowledge system doesn't have a KBA in German for the topic, but there is a KBA in English. In this case, you can designate the English document as the fallback document to answer the user’s question.

Use a JEXL-based expressions to define this type of filter.&#x20;

You can define these optional filters at the tenant level. `Settings` > `Configuration` > `Access Management` > `Access policy for optional attributes.`

<figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2FO8EUe0NHYAE6kDBcD2jI%2Fack.png?alt=media&#x26;token=9a968b4e-c49b-41a1-a460-0922d15ceff0" alt=""><figcaption><p>Using Optional Access Attributes</p></figcaption></figure>

#### Single value attribute <a href="#single-value-attribute" id="single-value-attribute"></a>

The expression for above example is: \
`(entity.language == null || entity.language == '' || entity.language == 'en' || entity.language == user.language)`

The restrictions we defined above are:

1. If the knowledge article does not have the attribute `language` then the user can view it \
   (`entity.language == null`)
2. If the knowledge article has an empty value for the attribute `language` then the user can view it\
   &#x20;(`entity.language == ''`)
3. If the knowledge article has a value and it is `en`(English) for the attribute `language` then the user can view it (`entity.language == 'en'`)
4. If the knowledge article has a value other than `en` then it should match user’s language to view the article. \
   (`entity.language == user.language`)

Where:

| `entity`   | This label/variable represents content Knowledge article |
| ---------- | -------------------------------------------------------- |
| `user`     | This label/variable represents user                      |
| `language` | This is access attribute of article and user             |
| `country`  | This is access attribute of article and user             |

#### Multi-value attributes <a href="#multi-value-attribute" id="multi-value-attribute"></a>

The Aisera platform uses the `compareList` system function to compare multiple value access attributes.&#x20;

If you want to filter content based on the access attribute `country,`you can define it as an array/multi-value. This will make the knowledge article relevant for multiple countries.

To compare the `country` attribute defined on knowledge articles with the user’s country, use this expression: `compareList(entity.country, user.country).`

The following example displays the way the `compareList` function compares lists/array/multi-value attributes. This is part of the code and cannot be changed without release.

```
var compareList = function(entityList, userList) {
    var matched = false;
    if (entityList == null || entityList.size() == 0) {
        matched = true;
    } else {
        if (userList == null || userList.size() == 0) {
            matched = false;
        } else {
            for (entityAttribute: entityList) {
                if (userList.contains(entityAttribute)) {
                    matched = true;
                    break;
                }
            }
        }
    }
    matched;
};
```

Optional filter can be used in many different use cases.

* For one of our customer, we wanted to filter content based on two attributes: `country` and `region`.&#x20;
* We wanted to use `region` as a back up of `country`. Therefore, if a knowledge article has `country` defined, then match it with the user profile’s `country`. But if `country` is not defined for a knowledge article, but `region` is defined, the match the user profile's `region`.&#x20;
* We configured such check like this:\
  &#x20;`(entity.country != null && entity.country.size() > 0 && compareList(entity.country, user.country)) || ((entity.country == null || entity.country.size() == 0) && (entity.region != null && entity.region.size() > 0 && compareList(entity.region, user.region)))`

```
(entity.country != null && entity.country.size() > 0 && compareList(entity.country, user.country)) || ((entity.country == null || entity.country.size() == 0) && (entity.region != null && entity.region.size() > 0 && compareList(entity.region, user.region)))
```

* The first part of expression is checking whether the knowledge article has a country attribute, then match.\
  `(entity.country != null && entity.country.size() > 0 && compareList(entity.country, user.country))`

```
(entity.country != null && entity.country.size() > 0 && compareList(entity.country, user.country))
```

* The second half checks when county is not defined but region is.\
  &#x20;`((entity.country == null || entity.country.size() == 0) && (entity.region != null && entity.region.size() > 0 && compareList(entity.region, user.region))`

```
((entity.country == null || entity.country.size() == 0) && (entity.region != null && entity.region.size() > 0 && compareList(entity.region, user.region))
```

### Passing Access Attributes in sessionVars <a href="#passing-access-attributes-in-sessionvar" id="passing-access-attributes-in-sessionvar"></a>

There are multiple way to pass information in sessionVars. One of them is via pre-handling flows.

SessionVar is map/property-bag/list of key value pair. Like this

`{ "userId" : "abc12", "company" : "Aisera" }`

Pass Access attributes with the `accessAttributes`property.&#x20;

This is a string-ified json call. Assume you want to send two access attributes `productLine` and `country` for a user. Make sure the label of each key matches the access attribute name. For example, `productLine` in the example below is the access attribute name.

`{ "productLine" : "duc1", "country" : "united states" }`

The code should be passed like this in the sessionVar:

`{ "userId" : "abc12", "company" : "Aisera", "accessAttributes": "{\"productLine\" : \"duc1\", \"country\" : \"united states\"}" }`

Javascript to update a sessionVar:

`sessionVars.put("accessAttibutes", "{\"productLine\" : \"duc1\", \"country\" : \"united states\"}"); return sessionVars;`

<div align="left"><figure><img src="https://3281977978-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvBFXjH9S1CAy9f5hzg5Q%2Fuploads%2Fmsj6RD2mHH6Sv91ZRw63%2Facl.png?alt=media&#x26;token=b5ead1c5-efe8-49cf-8500-7991f8f95fff" alt="" width="563"><figcaption><p>Defining Access Attributes as sessionVars</p></figcaption></figure></div>

## &#x20;<br>
