Permissioning

Note

Before going into details, an important clarification:

Permissions deal only with what is (or is not) displayed in the UI, it does NOT affect the state evaluation or the API calls.

App specific permissioning

Entire modules may be included or excluded from the app via permissioning.

This is a design time concern and is NOT user specific.

By default, all modules are available and presented in the UI (e.g. in the SettingsPanel) This can be customised with the modules prop of the component:

  1. Including only specific modules
<Adaptable.Provider
  {...restOfProps}
  modules={{
    include: ['theme', 'calculatedColumn', 'styledCell'],
  }}
>
  <Adaptable.UI />
</Adaptable.Provider>
  1. excluding specific modules (meaning: everything, but...)
<Adaptable.Provider
  {...restOfProps}
  modules={{
    exclude: ['flashingCell', 'styledCell'],
  }}
>
  <Adaptable.UI />
</Adaptable.Provider>

Note

The availability of a module wins over user permissions. More explicitly, a user can have access to a module but if that module is excluded, it won't be visible for the user, even if the user has the required permissions.

Note

By default, if a module is available, a user has all permissions that come with that module. However, if userInfo.auth is specified, that will override the default permissions.

Demo with modules.exclude
Fork

This demo is configured with the following modules excluded: ['styledCell', 'quickSearch', 'flashingCell'].

If you open the settings panel (by clicking the settings icon in the top-left corner), you will see that the excluded modules are not visible there.

Note

At any time you can re-render the <Adaptable.Provider /> component with a new value for the modules prop and the UI will be updated accordingly.

Available permissions

Note

Any permission may be negated (excluded from the authorised roles) by prepending it with !

For example, you can authorize a User with the "styledCellAdmin" role, so it will have all permissions on the Styled Cell Module (create, edit, addToView, etc.), except for "styledCell_delete"

Using permission negations
userInfo={{
  userId: 'ID_123456',
  userName: 'John Doe',
  auth: {
    roles: ['styledCellAdmin'],
    permissions: ['!styledCell_delete'],
  },
}}

To read more on permissions and how to use them, see Using the Authorization Framework section.

The following permissions are available (together with their negated versions):

Alert

  • "alert_create"
  • "alert_delete"
  • "alert_edit"
  • "alert_add_to_view"
  • "alert_remove_from_view"

Calculated Columns

  • "calculatedColumn_create"
  • "calculatedColumn_delete"
  • "calculatedColumn_edit"
  • "calculatedColumn_add_to_view"
  • "calculatedColumn_remove_from_view"

Export

  • "export_create"
  • "export_delete"
  • "export_edit"
  • "export_run"

Flashing Cell

  • "flashingCell_create"
  • "flashingCell_delete"
  • "flashingCell_edit"
  • "flashingCell_add_to_view"
  • "flashingCell_remove_from_view"

Grid Filter

  • "gridFilter_create"
  • "gridFilter_delete"
  • "gridFilter_edit"
  • "gridFilter_add_to_view"
  • "gridFilter_remove_from_view"

Styled Cell

  • "styledCell_create"
  • "styledCell_delete"
  • "styledCell_edit"
  • "styledCell_add_to_view"
  • "styledCell_remove_from_view"

Available roles

Note

A role is a collection of permissions that are granted together.

You can use permission negations if you want to grant all permissions in a role except for a specific one.

Using permission negations with roles
userInfo={{
  userId: 'ID_123456',
  userName: 'John Doe',
  auth: {
    roles: ['flashingCellAdmin','calculatedColumnAdmin'],
    permissions: ['!flashingCell_remove_from_view'],
  },
}}

To read more on permissions and how to use them, see Using the Authorization Framework section.

The following roles are available:

Alert

  • "alertAdmin" - has all the alert permissions

Calculated Column

  • "calculatedColumnViewer" - has the following permissions:
    • "calculatedColumn_add_to_view"
    • "calculatedColumn_remove_from_view"
  • "calculatedColumnAdmin" - has all the calculated column permissions

Export

  • "exportViewer" - has the "export_run" permission
  • "exportAdmin" - has all the export permissions

Flashing Cell

  • "flashingCellViewer" - has the following permissions:
    • "flashingCell_add_to_view"
    • "flashingCell_remove_from_view"
  • "flashingCellAdmin" - has all the flashing cell permissions

User specific permissioning

User session info may be provided via userInfo prop of the component:

Type definition for the userInfo prop
export type UserInformation = {
  userId: string;
  userName: string;
  auth?: UserAuthorization;
};
Type definition for the userInfo.auth prop
export type UserAuthorization = {
  // a list of roles or a function that returns a list of roles
  roles?: AdaptableRole[] | ((context: AuthContext) => AdaptableRole[]);

  // a list of permissions or a function that returns a list of permissions
  // NOTE: you can also use negated permissions here (eg: "!calculatedColumn_edit")
  permissions?:
    | (AdaptablePermission | NegatedAdaptablePermission)[]
    | ((context: AuthContext) => (AdaptablePermission | NegatedAdaptablePermission)[]);

  // optionally, you can provide a custom function to have the final say
  // on whether a user has a specific permission or not
  checkPermission?: (context: CheckPermissionContext) => boolean;
};
Configuring user specific permissioning via userInfo
<Adaptable.Provider
  {...restOfProps}
  userInfo={{
    userId: 'ID_123456',
    userName: 'John Doe',
    auth: {
      roles: ['styledCellAdmin'],
      permissions: ['calculatedColumn_edit'],
    },
  }}
  {...restOfProps}
>
  <Adaptable.UI />
</Adaptable.Provider>
Fork

This example is configured to only allow access to the Calculated Column module.

All other modules that expose permissions are disabled.

This is accomplished by configuring userInfo.auth.roles

<Adaptable.Provider
  {...restOfProps}
  userInfo={{
    userId: 'ID_123456',
    userName: 'John Doe',
    auth: {
      roles: ['calculatedColumnAdmin'],
    },
  }}
>
  <Adaptable.UI />
</Adaptable.Provider>

Authorization Framework

This may be customised using Adaptable's incredibly flexible authorisation framework, which is a variant of a role-based access control (RBAC) system:

  1. Some actions/UI controls are available only if the the user has specific permissions: e.g. "calculatedColumn_create", "calculatedColumn_delete", etc.

  2. Permissions are authorised for specific roles which Adaptable provides out of the box: e.g. Role "calculatedColumnAdmin" is authorised for permissions: "calculatedColumn_create", "calculatedColumn_delete", "calculatedColumn_edit", "calculatedColumn_add_to_view", "calculatedColumn_remove_from_view"

  3. Custom Role-Permission mappings may be provided via AdaptableProps.authRoles:

Configuring a custom Role-Permission mapping
<Adaptable.Provider
  authRoles={{
    calculatedColumnEditor: ['calculatedColumn_edit'],
  }}
  userInfo={{
    userId: 'ID_123456',
    userName: 'John Doe',
    auth: {
      roles: ['calculatedColumnEditor'],
    },
  }}
  {...restOfProps}
>
  <Adaptable.UI />
</Adaptable.Provider>
  1. Some object definitions may override the standard permissions with permission flags: editable, deletable.

Customising user permissioning

Note

If no userInfo.auth prop is provided, the user has all permissions for the available modules.

As soon as a custom UserAuthorization is provided via userInfo.auth, the user ONLY has the provided roles and/or permissions.

User specific permission checking is performed on 3 levels (3. has the highest priority, 1. the lowest):

  1. Declarative permissions defined via UserAuthorization.roles & UserAuthorization.permissions:

E.g. user has all permissions authorised for styledCellAdmin and additionally the calculatedColumn_edit permission

userInfo={{
  userId: 'ID_123456',
  userName: 'John Doe',
  auth: {
    roles: ['styledCellAdmin'],
    permissions: ['calculatedColumn_edit'],
  },
}}

Note

A specific permission may be negated (excluded from the authorised roles) by prepending it with !

e.g. User is authorised for all "styledCellAdmin" permission (create, edit, addToView, etc.), except for "styledCell_delete"

userInfo={{
  userId: 'ID_123456',
  userName: 'John Doe',
  auth: {
    roles: ['styledCellAdmin'],
    permissions: ['!styledCell_delete'],
  },
}}
  1. Custom object permission flags: editable, deletable e.g. even if a user has the "styledCell_delete" permission, it won't be able to delete a StyledCell definition with the deletable=false flag:
'style-cell-1': {
  label: 'style-cell-1',
  scope: {
    columns: ['name'],
  },
  style: {
    background: 'fuchsia',
  },
  permissions: {
    deletable: false,
  },
},
  1. Custom permission check function UserAuthorization.checkPermission?: (context: CheckPermissionContext) => boolean
export interface CheckPermissionContext extends BaseContext {
  adaptableId: string;
  userId: string;
  userName: string;
  permission: AdaptablePermission;
  defaultPermissionCheckResult: boolean;
  adaptableObject?: AdaptableObject<AdaptableObjectDef>;
  userPermissions: AdaptablePermission[];
}

If provided, the function will be invoked for each permission check and will override the default permission check result (which is provided in the params).

Using a custom permission check function
<Adaptable.Provider
  authRoles={{
    calculatedColumnEditor: ['calculatedColumn_edit'],
  }}
  userInfo={{
    userId: 'ID_123456',
    userName: 'John Doe',
    auth: {
      roles: ['styledCellAdmin', 'calculatedColumnAdmin', 'calculatedColumnEditor'],
      permissions: ['!calculatedColumn_edit'],
      checkPermission: (context: CheckPermissionContext) => {
        if (context.permission === 'calculatedColumn_add_to_view') {
          return invokeSomeExternalService(context.userId, context.permission);
        }
        return context.defaultPermissionCheckResult;
      },
    },
  }}
  {...restOfProps}
>
  <Adaptable.UI />
</Adaptable.Provider>