Chapter 5. Customization

Table of Contents

Access Control Lists (ACLs)
Introduction
Definition
Examples
Reference
Process Management
Introduction
Example process
Recording the demand
Approval by manager
Processing by purchasing department
Processing by the mail room
Implementing the example
Process (as a container)
Activity Dialogs
Transitions
Transition Actions
Activities
Book ordering process Path
Process configuration reference
Process
Activity
ActivityDialog
Transition
Transition Actions
Access Control Lists (ACLs)
Creating your own themes
Localization of the OTRS frontend

Access Control Lists (ACLs)

Introduction

From OTRS 2.0 on, Access Control Lists (ACLs) can be used to control access to tickets, modules, queues, etc., or to influence actions on tickets (closing, moving, etc.) in certain situations. ACLs can be used to supplement the existing permission system of roles and groups. Using ACLs, rudimentary work-flows within the system can be mapped, based on ticket attributes.

In a general way ACLs are used to reduce the possible options for a ticket based on a defined set of rules.

ACLs can be directly entered into the Kernel/Config.pm file. whoever this is not any more recommended as OTRS comes now with a GUI Access Control Lists in the Admin panel that allows to save the ACLs in the Database as the first step and then deploy them into a file when they are ready.

This chapter has some ACL examples which will walk you trough the process of defining ACL definitions, and a reference of all possible important ACL settings.

Warning

The default user 'root@localhost' is not affeced by the Ticket ACls

Definition

The ACL definition can be split into two big parts, 'Matching' and 'Change'. In the matching sections the ACLs contains attributes that has to be met in order to use the ACL, if the attributes defined in the ACL does not match with the attributes that are sent, then the ACL does not take any affect, but any other match ACL will. The change sections contains the rules to reduce the possible options for a ticket.

Matching Sections

  • Properties

    This section contains matching options that can be changed on the fly, for example on a ticket creation time the data of the ticket changes dynamically as the agent sets the information, if an ACL is set to match a ticket attribute then only when the matching attribute is selected the ACL will be active and might reduce other ticket attributes, but as soon as another value is selected the ACL will not take any affect.

  • PropertiesDatabase

    This section is similar to 'Properties' but does not take changes in ticket attributes that are not saved into the DataBase, this means that changing an attribute without submit will not make any affect. This section is not use for ticket creation screens (as tickets are not yet created in the Database).

Change Sections

  • Possible

    Possible section resets the data to be reduce to only the elements that are set in this section.

  • PossibleAdd

    Elements in PossibleAdd section add missing elements that where reduced in other ACLs. PossibleAdd is only used in together with other ACLs that have Possible or PossibleNot sections.

  • PossibleNot

    This section is used to remove specific elements from the current data. It could be used stand alone or together with other ACLs with a Possible or PossibleAdd sections.

In order to make the development of ACLs easier and more powerful there is a set of so called modifiers for the attributes on each section. This modifiers as explained below:

Modifiers

  • [Not]

    This modifier is used to negate a value for example: '[Not]2 low' in this case talking about ticket priorities will be the same as to have: '1 very low', '3 normal', '4 high', '5 very high'.

  • [RegExp]

    It is use to define a regular expression for matching several values, for example '[RegExp]low' talking about priorities is the same as '1 very low', '2 low'.

  • [regexp]

    It is very similar to [RegExp] but it is case insensitive.

  • [NotRegExp]

    Negated regular expressions for example '[NotRegExp]low' talking about priorities is the same as '3 normal', '4 high', '5 very high.

  • [Notregexp]

    It is very similar to [NotRegExp] but it is case insensitive.

Examples

The following examples are shown in both ways graphical and text based.

Example 5.1. ACL allowing movement into a queue of only those tickets with ticket priority 5.

This example shows you the basic structure of an ACL. First, it needs to have a name. In this case, it is "ACL-Name-2". Note that the ACLs will be numerically sorted before execution, so you should use the names carefully.

Secondly, you have a "Properties" section which is a filter for your tickets. All the criteria defined here will be applied to a ticket to determine if the ACL must be applied or not. In our example, a ticket will match if it is in the queue "Raw" and has priority "5 very high". This is also affected by changes in the form (e.g. if the ticket is the queue "raw" and had a priority "3 normal" at this moment the ACL will not match, but then priority drop-down is selected and the priority is changed now to "5 very high" then will also match).

Lastly, a section "Possible" defines modifications to the screens. In this case, from the available queues, only the queue "Alert" can be selected in a ticket screen.

# ticket acl
$Self->{TicketAcl}->{'100-Example-ACL'} = {
    # match properties
    Properties => {
        # current ticket match properties
        Ticket => {
            Queue => ['Raw'],
            Priority => ['5 very high'],
        }
    },
    # return possible options (white list)
    Possible => {
        # possible ticket options (white list)
        Ticket => {
            Queue => ['Alert'],
        },
    },
};
                


Example 5.2.  ACL allowing movement into a queue of only those tickets with ticket priority 5 stored in the database.

This example is very similar to the last one, but in this case only tickets in the queue "Raw" and with a priority "5 very high", both stored in the database will match. This kind of ACLs does not consider changes in the form before the ticket is really updated in the database.

# ticket acl
$Self->{TicketAcl}->{'102-Example-ACL'} = {
    # match properties
    PropertiesDatabase => {
        # current ticket match properties
        Ticket => {
            Queue => ['Raw'],
            Priority => ['5 very high'],
        }
    },
    # return possible options (white list)
    Possible => {
        # possible ticket options (white list)
        Ticket => {
            Queue => ['Alert'],
        },
    },
};
                


Example 5.3.  ACL disabling the closing of tickets in the raw queue, and hiding the close button.

Here you can see how a ticket field (state) can be filtered with more than one possible value to select from. It is also possible to limit the actions that can be executed for a certain ticket. In this case, the ticket cannot be closed.

$Self->{TicketAcl}->{'102-Second-Example-ACL'} = {
    # match properties
    Properties => {
        # current ticket match properties
        Ticket => {
            Queue => ['Raw'],
        }
    },
    # return possible options (white list)
    Possible => {
        # possible ticket options (white list)
        Ticket => {
            State => ['new', 'open', 'pending reminder'],
        },
    },
    3 return also not possible options (black list)
    PossibleNot => {
        # not possible action options
        Action => [ 'AgentTicketClose' ],
    },
};
                


Example 5.4. ACL removing always state closed successful.

This example shows how it is possible to define negative filters (the state "closed successful" will be removed). You can also see that not defining match properties for a ticket will match any ticket, i. e. the ACL will always be applied. This may be useful if you want to hide certain values by default, and only enable them in special circumstances (e. g. if the agent is in a specific group).

$Self->{TicketAcl}->{'103-Third-ACL-Example'} = {
    # match properties
    Properties => {
        # current ticket match properties (match always)
    },
    # return possible options
    PossibleNot => {
        # possible ticket options
        Ticket => {
            State => ['closed successful'],
        },
    },
};
                


Example 5.5.  ACL only showing Hardware services for tickets that are created in queues that start with "HW".

This example also shows you how you can use regular expressions for matching tickets and for filtering the available options.

$Self->{TicketAcl}->{'104-Only-Hardware-Services-for-HW-Queues-ACL'} = {
    # match properties
    # note we don't have "Ticket => {" because there's no ticket yet
    Properties => {
    Queue => {
        Name => ['[RegExp]HW'],
        }
    },
    # return possible options
    Possible => {
        # possible ticket options
        Ticket => {
            Service => ['[RegExp]^(Hardware)'],
        },
    },
};
                


Example 5.6.  ACL to restrict a Process in the customer frontend using the CustomerID.

$Self->{TicketAcl}->{"105-Disallow-Process-For-CustomerID"} = {
    'Possible' => {},
    'PossibleNot' => {
        'Process' => [
            'P14'
        ]
    },
    'Properties' => {
        'CustomerUser' => {
            'UserCustomerID' => [
                'CustomerID'
            ]
        }
    },
    'PropertiesDatabase' => {},
    'StopAfterMatch' => 0
};
                


Reference

In the example below there is a list of all parameters which can be used for ACLs.

Please see the section on ACLs in the ProcessManagement documentation for a detailed description of how to use ACLs for process tickets.

Example 5.7. Reference showing all possible important ACL settings.

# ticket acl
$Self->{TicketAcl}->{'200-ACL-Reference'} = {
    # match properties (current values from the form)
    Properties => {

        # the used frontend module
        Frontend => {
            Action => ['AgentTicketPhone', 'AgentTicketEmail'],
        },

        # the logged in agent
        User => {
            UserLogin => ['some login'],
            Group_rw => [
                'hotline',
            ],
            Role => [
                'admin',
            ],
            # ...
        },

        # the logged in customer
        CustomerUser => {
            UserLogin => ['some login'],
            UserCustomerID => ['some customer id'],
            Group_rw => [
                'hotline',
            ],
            Role => [
                'admin',
            ],
            # ...
        },

        # process properties
        Process => {
            ProcessEntityID        => ['Process-9c378d7cc59f0fce4cee7bb9995ee3eb'],         # the Process that the current ticket is part of
            ActivityEntityID       => ['Activity-f8b2fdebe54eeb7b147a5f8e1da5e35c'],        # the current Activity of the ticket
            ActivityDialogEntityID => ['ActivityDialog-aff0ae05fe6803f38de8fff6cf33b7ce'],  # the current ActivityDialog that the Agent/Customer is using
        },

        # ticket properties
        Queue => {
            Name     => ['Raw'],
            QueueID  => ['some id'],
            GroupID  => ['some id'],
            Email    => ['some email'],
            RealName => ['OTRS System'],
            # ...
        },
        Service => {
            ServiceID => ['some id'],
            Name      => ['some name'],
            ParentID  => ['some id'],
            # ...
        },
        Type => {
            ID   => ['some id'],
            Name => ['some name'],
            # ...
        },
        Priority = {
            ID   => ['some id'],
            Name => ['some name'],
            # ...
        },
        SLA = {
            SLAID    => ['some id'],
            Name     => ['some name'],
            Calendar => ['some calendar'],
            # ...
        },
        State = {
            ID       => ['some id'],
            Name     => ['some name'],
            TypeName => ['some state type name'],,
            TypeID   => ['some state type id'],
            # ...
        },
        Owner => {
            UserLogin => ['some login'],
            Group_rw => [
                'some group',
            ],
            Role => [
                'admin',
            ],
            # ...
        },
        Responsible => {
            UserLogin => ['some login'],
            Group_rw => [
                'some group',
            ],
            Role => [
                'admin',
            ],
            # ...
        },
        DynamicField => {
            # Names must be in DynamicField_<field_name> format.
            # Values in [ ... ] must always be the untranslated internal data keys
            #   specified in the dynamic field definition and
            #   not the data values shown to the user.
            DynamicField_Field1          => ['some value'],
            DynamicField_OtherField      => ['some value'],
            DynamicField_TicketFreeText2 => ['some value'],
            # ...
        },
        # alternatively, ticket properties can be specified in the ticket hash
        Ticket => {
            Queue                => ['Raw'],
            State                => ['new', 'open'],
            Priority             => ['some priority'],
            Lock                 => ['lock'],
            CustomerID           => ['some id'],
            CustomerUserID       => ['some id'],
            Owner                => ['some owner'],
            DynamicField_Field1  => ['some value'],
            DynamicField_MyField => ['some value'],
            # ...
        },
    },

    # match properties (existing values from the database)
    PropertiesDatabase => {
        # See section "Properties", the same config can be used here.
        # ...
    }

    # reset possible options (white list)
    Possible => {
        # possible ticket options (white list)
        Ticket => {
            Queue => ['Hotline', 'Coordination'],
            State => ['some state'],
            Priority => ['5 very high'],
            DynamicField_Field1  => ['some value'],
            DynamicField_MyField => ['some value'],
            # ...
            NewOwner => ['some owner'],
            OldOwner => ['some owner'],
            # ...
        },

        # Limit the number of possible ActivityDialogs the Agent/Customer
        #   can use in a process ticket.
        ActivityDialog => ['AD1', 'AD3'],

        # Limit the number of possible Processes that can be started
        Process => ['Process-9c378d7cc59f0fce4cee7bb9995ee3eb', 'Process-12345678901234567890123456789012'],

        # possible action options (white list)
        Action => [
            'AgentTicketBounce',
            'AgentTicketPhone'.      # only used to show/hide the Split action
            'AgentLinkObject',       # only used to show/hide the Link action
            # ...
        ],
    },
    # add options (white list)
    PossibleAdd => {
        # See section "Possible"
        # ...
    },
    # remove options (black list)
    PossibleNot => {
        # See section "Possible"
        # ...
    },
};
                


Note

While matching ACLs if CustomerUserID parameter sent, the ACL mechanism will compare the defined ACLs using the supplied CustomerUserID to gather the CustomerUser details to fill the CustomerUser hash and it also overrides the Customer information in the Ticket hash for the Properties match. On the other hand this calculations are also made for the PropertiesDatabase part, but using the Ticket Customer as the basis to gather the data.

Notice that in Customer Interface, the CustomerUserID is always sent with the current logged Customer User.

Be aware that in ticket search screens (AgentTicketSearch and CustomerTicketSearch) the only affected attributes by ACLs are the Dynamic Fields. This means that this screens you can not restrict any other attribute like ticket type, state, queue, etc.

From OTRS 4 the 'Action' parameter is not longer a hash but an array reference and it can be used in any of the Change sections using any of the Modifiers.