Setting Up Permissions and Roles

Prior to version 2021.3.0, data security was configured within the technical administration and required programming skills to define security rules.

Starting from version 2021.3.0, application provides a mechanism for securing data access without requiring access to the technical admin interface, nore specific programming knowledge.

Requirements

  • Plugin PACKAGED_Security installed and activated

  • Structures pkgsecugroup and pkgsecupermission restored on application

  • Make use of plugin provided macros in security rules

  • Eligible structures must be identified

Overview

Permissions pkgsecupermission

A permission represents an authorized action.

Permission are defined by giving a functional name (property name) and a permission key (property permission).

A permission grants a right for a context. The given right is resolved by analyzing the permission property. Permission follows the following pattern:

<version>/<domain>/<action>/[modifiers]+

Example: A pkgsecupremission instance is defined with following with properties:

  • name: “Update owned offline“

  • permission: v1/objectdata/update/$offline/$selfowner

Such permission grants to update instances in an offline status (status is not online and not archived) that the operating user owns (object.owner == surfer.id)

Patterns

  • version: The only available version for patterns is v1 but introducing a version in patterns will ease further improvements and ease ascendent compatibility. Until new versions are available, just keep in mind that natively handled permissions start with “v1”.

  • domain: The domain of the security rule that this permission will act on. As of 2021.3.0, objectdataand boards are handled.
    Since 2022.3, objectactions and applications domain are handled

  • action: The action within the domain that this permission will act on. As of 2021.3.0, all actions from objectdata domain can be handled.
    Since 2022.3, new actions added to objectdata and objectactions are handled.

  • modifiers: Modifiers will define the context for which the action will be granted. Modifiers vary from one action to the other:

    • objectdata

      • insert action: 1 modifier is to be defined: creationMode. Therefore, all insert permissions follow this pattern: v1/objectdata/insert/<creationMode>

      • changestatus action: 3 modifiers are to be defined: workflowAction, instanceStatus, ownership. Therefore, all changestatus permissions follow this pattern: v1/objectdata/changestatus/<workflowAction>/<instanceStatus>/<ownership>

      • other objectdata actions (delete, i18nfieldstranslate, order, retrievecaption, update, view): 2 modifiers are to be defined: instanceStatus, ownership. Therefore, all those actions follow this pattern: v1/objectdata/<action>/<instanceStatus>/<ownership>

    • boards

      • makepublicboard action: No modifiers - permission is granted or not

      • shareboard action: 3 modifiers are to be defined: boardVisibility, boardType, ownership,

    • applications (since 2022.3)

      • isavailable action: 1 modifier is to be defined: applicationName. Therefore, all isavailable permissions follow this pattern: v1/applications/isavailable/<applicationName>

Modifiers

Each modifier supports specific keywords to finely define the context.

boardVisibility

Allows to limit permission based on boards visibility:

  • $publicboard: Grants permission on a public board (private = 2)

  • $privateboard: Grants permission on a private board (private = 1)

  • $anyvisibilityboard: Grants permission regardless of visibility

boardType

Allows to limit permission based on the type of board:

  • $anyboardtype: Grants permission on any type of board

  • <type>: Grants permission on board of type <type>

creationMode

Creation mode represents how the instance is created. 3 keywords are available:

  • $newcreation: Creating a fresh instance (eg click on the “New” button)

  • $copycreation: Create an instance by duplicating an existing one or by creating a workcopy

  • $anycreation: Any creation mode

workflowAction

Workflow action represents the action that is performed on the object from a workflow perspective. 6 keywords are available:

  • $publish: Publishing action: performing a workflow action that will move the instance in an online marked state

  • $archive: Archiving action: performing a workflow action that will move the instance in an archived marked state

  • $forward: Forward action: performing an action marked forward, and that will not lead to online or archived marked state.

  • $backward: Backward action: performing an action NOT marked forward, and that will not lead to online or archived marked state.

  • $process: Any process action: performing that will not lead to online or archived marked state.

  • $anyaction: Any workflow action (including publishing and archiving actions)

  • <actionName>: If none of the above keywords, the action name is taken as is and resolved base on the instance’s workflow

instanceStatus

Instance status represents the current status of the object from a workflow perspective. 5 keywords are available:

  • $online: An online marked state

  • $archived: An archived marked state

  • $offline: A state that is neither marked online not archived

  • $initialstatus: The initial state of the instance (usually = 2)

  • $anystatus: Any state

  • <customMetaStatus>: It is possible to create custom names regrouping several states (see further)

  • <statusID>: It is possible to reference a status ID directly (New in 2022.3.0 )

ownership

Ownership allows to limit a permission to the owner property of an instance. 7 keywords are available

  • $selfowner: User must be the owner of the instance to be able to perform an action

  • $anyowner: No restriction on ownership

  • $boardcollaborator: Specific to boards domain - Identify the surfer as a collaborator on a board

  • $teammember: since 2024.1 Allows to check whether the surfer is part of the field team (team is a child multi on user). This requires the structure to have the pkg/security/collaborative config tag

  • $teamleader: since 2024.1Allows to check whether the surfer is denoted in the field jobowner. This requires the structure to have the pkg/security/collaborative config tag

  • $teamviewer: since 2024.4Allows to check whether the surfer is part of the field viewers (viewers is a child multi on user). This requires the structure to have the pkg/security/collaborative config tag.
    Caution, $teamviewer ownership can only be used with view action

  • $public: since 2024.4Allows to check whether the instance is NOT private →private field as a child activated = 2. This requires the structure to have the pkg/security/collaborative config tag.

Groups pkgsecugroup

Groups allow to centralize multiple permissions on one or many objects, for one or many roles and one or many users.

  • name: Name of the group

  • template (boolean): it is convenient to have groups as templates. If template is true, then this instance is not used when resolving groups to which belong a user

  • activated (boolean): Inactive instances are ignored

  • objectsselector (string): A structure selector to define which objects are managed by the group. For instance:

    • assetkeyword would apply to structure named assetkeyword.

    • #damobject would apply to any structure having the tag damobject (on table level)

    • assetkeyword,#damobject would apply to structure assetkeyword and to any object having the tag damobject

  • permissions (childmulti → pkgsecupermission): Permissions granted to users belonging to this group for objects matching objectselector

  • roles (childmulti →role): All users of selected roles will be members of the group

  • users (childmulti →user): All users selected will be members of this group

When defining a group as a template, properties objectsselector, roles and users will not be editable anymore. Creating templates is quite handy as you can think about it as being a group of permissions. It is recommended to create templates such as “[VIEWER]“, [CONTRIBUTOR]” or “[MANAGER]” and to link the typical permissions granted to such a group.

To avoid security issues, not all structures are eligible to this mechanism. To be able to grant a permission on a structure, the table MUST have the appropriate tags.

It is not possible to add users through their group. Users can only be assigned through their role or directly

Identifying eligible structures

Structures eligibles to permission granting are marked with one or multiple table tags :

pkg/security/secugroup/<action> or pkg/security/secugroup/all

this means that to be able to manage view permissions on object foo, foo table configuration must have either pkg/security/secugroup/view or pkg/security/secugroup/all

Installing the feature

Initializing data

The default NAR file contains the required structures for managing the rights, but to ease migrations, and upgrades, the NAR file does not contains neither permissions definitions nor groups:

Providing default values would force some ids with functional meanings on permissions, groups, roles and eventually users, which is obviously not desired as each projects needs defines different roles, each project will make use of some permissions, but not all the possible ones…

Additionally, delivering configured permissions or groups directly in the NAR file would increase migration complexity as product added permissions and product added groups might come in conflict with projects definitions.

As the whole system only relies on permission strings, a service API is provided to “fill the gap” between actual values in DB and what the product team recommends to create:

/api/packaged/admin/security/update

This API requires Administrators or TestOperators HTTP role to be executed as well as the right to create instances of pkgsecupermission and pkgsecugroup

This API will check current data in pkgsecupermission and pkgsecugroup and create missing data in both structures. Additional information is provided in the swagger UI.

  • permissions are identified based on the permission string

  • groups are identified based on their name.

Product team will only provide templates for groups. Product team will always give template names with brackets.

It is recommended to identify project specific template with either a prefix or a suffix

Make usage of the permissions

Permissions handled by the plugin are just a tool allowing to give you more flexibility to your rules, but they can be combined with any project specific rules.

The plugin provides a security macro per domain with the camel-cased name pkg<version><domain>. These macro will be installed first time you activate the plugin.

You will need to make usage of these macros in your security rules:

For instance on objectdata/update, you can define a single rule “Packaged updates“ with following code:

@pkgV1Objectdata('update')

Of course you might have more specific rules regarding users' rights on specific objects, but you can always use the macros as a starting point:

For instance, this call is perfectly fine

STRUCTUREHASTAG(objectname, 'damobject') AND NBCOMMONELEMENTS(object.someproperty, surfer.someproperty) > 0 AND @pkgV1Objectdata('update')

You could even add additional rules like to be able to update an object, you should be allowed to view it. In such a case, the rule could be written as

In objectdata/update, rule “To update, must also be allowed to view”

@pkgV1Objectdata('view') AND @pkgV1Objectdata('update')

Adapting PreparedWhere

As of 2021.3.0, the engine is not able to parse the security rules to augment SQL where clauses. While such improvement could be introduced in a future version of the engine, the PACKAGED_Security plugin leverages on AbstractPreparedWhereBusinessService to resolve bases according to users’ given permissions:

2 contexts are available:

  • base_pkgsecurity_view will return a PreparedWhere following user’s given VIEW permissions

  • base_pkgsecurity_update will return a PreparedWhere following user’s given UPDATE permissions

Extend existing bases

It is possible to automatically extend some bases with the ones provided by the plugin:

  1. Set plugin parameter extend_bases to true

  2. Make sure extended_bases references to the coma-separated list of bases you want the plugin to extend (base_list,base_search by default)

  3. Make sure extend_with references the coma-separated list of bases you want to use to extend the extended_bases list of bases (base_pkgsecurity_view by default)

By doing so, you will be instructing the plugin to extend base_list and base_search with base_pkgsecurity_view for each object.

In order to work around those issues, you can configure extended_bases_config to manage in a better way the configuration: this parameter accepts either null (no config) or a JsonArray to overwrite base extensions settings on objectselector + role context:

Each entry of the JsonArray MUST be a JsonObject that accepts the following properties:

  • objectSelector: A selector for object(s) impacted by the item. If not provided or null, all objects are impacted

  • roles: A JsonArray of String referencing the roles that are impacted by this item. If null or not provided, all roles will be impacted

  • extendedBases: A JsonArray of String referencing the bases (contextnames) for which extension is changed. If null or not provided, the value from plugin parameter extended_bases is used.

  • extendWithBases: A JsonArray of String referencing the bases that should be added to extendedBases to extend them. If null or not provided, the value from plugin parameter extend_with is used.

During the resolution of a base, JsonObjects are processed in given order. If the JsonObject matches the context (objectsSelector, roles from surfer, currentResolvedBase is part of extendedBases, then the bases used for extending the base is redefined to value of extendWithBases)

Examples

Preventing bases for Developers to be extended

Given that

  1. extend_bases = true

  2. extended_bases = base_list,base_search

  3. extend_with = base_pkgsecurity_view

To deactivate the extension for all objects for role 4 (and therefor to be able to see any instance), you can define the config to:

for role 4, you want to redefine extendWithBases to an empty list

Preventing some objects bases to be extended for some roles

This can be quite handy if you don’t want to allow some objects to be accessible to permissions management:

 

Make usage of those bases programatically

You can easily make use of those context to augment base_list, base_edit_list, base_search… in your project accordingly:

Extending capabilities

Meta statuses definitions

Quite often, you will need to identify workflow statuses as specific, but will not be able to rely on native keywords. For instance, you might want to identify what are the “validation steps” to be able to create permissions that will only apply to those statuses.

You can achieve this by configuring the plugin parameter meta_statuses:

This parameter is JSON. It accepts either null or a JsonObject.

If null, then no specific “metastatuses” are defined.

If a JsonObject, each key is a metaStatus name (exemple: “validationStep”). Associated value can be either

  • an array of ids that corresponds to ids matching the metastatus

  • an object for which each key is the name of a workflow or default ; metastatuses will then be resolved based on the workflow name or default if not found

Custom permission resolver

It is possible to configure a specific groovy script to resolve permissions in the surfer:

In plugin, configure custom_permissions_builder to the SAN based groovy script path to your desired implementation. (When saving, the groovy script will be created if not exists, with sample code)

Troubleshooting

Datamodel compliance

You can check the compliance of your data model by accessing

/api/packaged/admin/security/validators/model/html

  • if first line is green, the data model is good

  • if first line is yellow, you could improve it

  • if first line is red, it won’t work

Testing a user

You can check what the plugin has resolved for a user by calling

/api/packaged/admin/security/surfer-keys/<userId>

You can check the bases resolved by the plugin for a user by calling

/api/packaged/admin/security/surfer-bases/<userId>

New in 2022.3.0

New handled actions in objectdata domain

Following actions were added to objectdata domain and can be handled with @pkgV1Objectdata

  • broadcastVideo

  • defineVideoPoster

  • editPicture

  • editVideoChapters

  • editVideoSubtitles

  • embed

  • manageVideoCallToActions

  • manageVideoRolls

  • order

  • sliceVideo

All these actions follow the pattern v1/objectdata/<action>/<instanceStatus>/<ownership>

New handled domains

From 2022.3.0 some new domains are handled through new macros. Find below how these domains are handled.

Domain applications

applications domain defines one action isAvailable allowing to grant access on an application base on a code (parameter applicationname).

By default, the BackOffice application has for code bo, portal front-end has for code portal, Office pickers have for code officeassetpicker and all other pickers have for code assetpicker.

Permissions for this action have the pattern:

v1/applications/<action>/<applicationname>. As only one action is available as of 2022.3.0 , the pattern can be simplified to v1/applications/isavailable/<applicationname>

The macro @pkgV1Applications handles permissions checks. Note that as others PACKAGED_Security macros, the action ne is to be passed as an argument:

 

Domain objectactions

objectactions domain allows to define permissions on actions on an object type, with no restriction on an instance. Its primary goal is to help displaying actions triggers targeting multiple objects.

PACKAGED_Security plugin provides a new macro for handling objectactions domain actions: @pkgV1ObjectActions. As for @pkgV1Objectdata, this macro takes one argument: the name of the action to test permissions for.

@pkgV1ObjectActions is defined to check for an objectname if some permissions were given to a user for the corresponding objectdata action → No additional configuration is required on objectactions: an action from objectactions domain will be granted if some permissions were given on objectdata

Equivalences

objectactions action domain

tested objectdata action

 

objectactions action domain

tested objectdata action

 

create

insert

Check for existence of either

objectdata/insert/$anycreation
or
objectdata/insert/$newcreation

damimport

massimport

multiupdate

update

Check for existence of
objectdata/update/*

datavaluespicker

broadcastVideo

broadcastVideo

Check for existence of
objectdata/broadcastvideo/*

defineVideoPoster

defineVideoPoster

Check for existence of
objectdata/definevideoposter/*

delete

delete

Check for existence of
objectdata/delete/*

editPicture

editPicture

Check for existence of
objectdata/editpicture/*

editVideoChapters

editVideoChapters

Check for existence of
objectdata/editvideochapters/*

editVideoSubtitles

editVideoSubtitles

Check for existence of
objectdata/editvideosubtitles/*

embed

embed

Check for existence of
objectdata/embed/*

manageVideoCallToActions

manageVideoCallToActions

Check for existence of
objectdata/managevideocalltoactions/*

manageVideoRolls

manageVideoRolls

Check for existence of
objectdata/managevideorolls/*

order

order

Check for existence of
objectdata/order/*

sliceVideo

sliceVideo

Check for existence of
objectdata/slicevideo/*

Cheat sheet

Find for each managed domain / action, the permission pattern

domain

action

permission pattern

domain

action

permission pattern

applications

isAvailable

v1/applications/isavailable/:applicationName

boards

makePublicBoard

v1/boards/makepublicboard

boards

shareBoard

v1/boards/shareboard/:boardVisibility/:boardType/:ownership

objectdata

broadcastVideo

v1/objectdata/broadcastvideo/:instanceStatus/:ownership

objectdata

changeStatus

v1/objectdata/changestatus/:workflowAction/:instanceStatus/:ownership

objectdata

defineVideoPoster

v1/objectdata/definevideoposter/:instanceStatus/:ownership

objectdata

delete

v1/objectdata/delete/:instanceStatus/:ownership

objectdata

editPicture

v1/objectdata/editpicture/:instanceStatus/:ownership

objectdata

editVideoChapters

v1/objectdata/editvideochapters/:instanceStatus/:ownership

objectdata

editVideoSubtitles

v1/objectdata/editvideosubtitles/:instanceStatus/:ownership

objectdata

embed

v1/objectdata/embed/:instanceStatus/:ownership

objectdata

i18nFieldsTranslate

v1/objectdata/i18nfieldstranslate/:instanceStatus/:ownership

objectdata

insert

v1/objectdata/insert/:creationMode

objectdata

manageVideoCallToActions

v1/objectdata/managevideocalltoactions/:instanceStatus/:ownership

objectdata

manageVideoRolls

v1/objectdata/managevideorolls/:instanceStatus/:ownership

objectdata

order

v1/objectdata/order/:instanceStatus/:ownership

objectdata

retrieveCaption

v1/objectdata/retrieveCaption/:instanceStatus/:ownership

objectdata

sliceVideo

v1/objectdata/slicevideo/:instanceStatus/:ownership

objectdata

update

v1/objectdata/update/:instanceStatus/:ownership

objectdata

view

v1/objectdata/view/:instanceStatus/:ownership

Find available values for modifiers

modifier

value

description

modifier

value

description

applicationName

<name>

Name of the application (BackOffice → bo...)

boardVisibility

$publicboard

A board that is not private

 

$privateboard

A private board

 

$anyvisibilityboard

A board private or not

boardType

$anyboardtype

Any type of board

 

<type>

A board of type <type>

creationMode

$newcreation

Only fresh new instances

 

$copycreation

Only copies

 

$anycreation

Any mode

instanceStatus

$online

An online marked state

 

$archived

An archived marked state

 

$offline

A state that is neither marked online not archived

 

$initialstatus

The initial state of the instance (usually = 2)

 

$anystatus

Any state

 

<customMetaStatus>

A custom meta state

 

<statusID>

The ID of a status

ownership

$selfowner

User must be the owner of the instance to be able to perform an action

 

$anyowner

No restriction on ownership

 

$boardcollaborator

Specific to boards domain - Identify the surfer as a collaborator on a board

 

$teamleader

User is referenced on jobowner field (child → user)

Requires pkg/security/collaborative on structure

since 2024.4

 

$teammember

User is referenced on team field (cmlr → user)

Requires pkg/security/collaborative on structure

since 2024.4

 

$teamviewer

User is referenced on viewers field (cmlr → user)

Requires pkg/security/collaborative on structure

since 2024.4

 

$public

Instance has property private equals to false

Requires pkg/security/collaborative on structure

since 2024.4

workflowAction

$publish

Publishing action: performing a workflow action that will move the instance in an online marked state

 

$archive

Archiving action: performing a workflow action that will move the instance in an archived marked state

 

$forward

Forward action: performing an action marked forward, and that will not lead to online or archived marked state.

 

$backward

Backward action: performing an action NOT marked forward, and that will not lead to online or archived marked state.

 

$process

Any process action: performing that will not lead to online or archived marked state.

 

$anyaction

Any workflow action (including publishing and archiving actions)

 

<actionName>

If none of the above keywords, the action name is taken as is and resolved base on the instance’s workflow

Further reading

Rights and rolesarchived To learn how the default application is configured in terms of roles and permissions

Roles & Permissions To learn how you can use a dedicated user interface to configure roles and permissions