Please enlarge your browser's window to experience the pleasure of this sweet little blog.

OTRS LDAP Authentication for Agents and Customers

Probably many of you have or still are actively using the open-source, ITIL compliant trouble ticket system named OTRS. And probably some of you also might have experienced the pleasure of setting up the software once – and know the pain.

OTRS as a product is pretty cool and full of features, unfortunately from a technical aspect it’s pretty much of an unaesthetic “Perl hack” that’s, especially when you should try to integrate it into your existing environments and make it talk to your RADIUS or directly to your LDAP. Here, I would like to describe the basic configuration to get the latter working without any troubles.

Everything actually starts within the $OTRSHOME/Kernel/Config.pm. After you’ve set up your Apache to get you displayed the /otrs/index.pl and /otrs/customer.pl you’ll need to start hacking Perl in OTRS’ “config file”.
Let’s say, that we would want to authenticate against LDAP. And maybe not only for the agents (the people using index.pl) but also for the customers. So, let’s assume that we’re having a LDAP-tree containing our Base (“dc=something,dc=com”) and our “Users” OU (“ou=Users,dc=something,dc=com”). Also, we have a “Groups” OU (“ou=Groups,dc=something,dc=com”). I think that’s probably the most common built-up, regardless what names the OUs actually have.

Now, first of all, we need to know what user we could use to authenticate on our LDAP later and get the information we need. Here, I’m assuming it’s “cn=admin,dc=something,dc=com”. Let’s begin with the configuration for getting the agents authenticated:

    $Self->{'AuthModule'} = 'Kernel::System::Auth::LDAP';
    $Self->{'AuthModule::LDAP::Host'} = 'localhost';
    $Self->{'AuthModule::LDAP::BaseDN'} = 'dc=something,dc=com';
    $Self->{'AuthModule::LDAP::UID'} = 'uid';
    $Self->{'AuthModule::LDAP::GroupDN'} = 'cn=otrsagent,ou=Groups,dc=something,dc=com';
    $Self->{'AuthModule::LDAP::UserAttr'} = 'UID';
    $Self->{'AuthModule::LDAP::AccessAttr'} = 'memberUid';
    $Self->{'AuthModule::LDAP::Params'} = {
        port => 389,
        timeout => 120,
        async => 0,
        version => 3,
    };

The configuration should be pretty self-describing, though let’s sum it up: We’re connecting to the LDAP host “localhost” (since we probably tunnel the SSH port to the OTRS machine or have it running directly on that one – else you’d just need to specify another hostname/IP. BEWARE: When using an external LDAP with no tunnel you should use LDAPS!) and use our BaseDN. We define the user-id field being named “uid”, just like the user-attribute we’re going to look-up and we’ll be using the memberUid as access-attribute. Wait. memberUid? I lost you, right?

In this configuration, we’re also using a GroupDN that actually lets us “filter” which of our users might be allowed to use the OTRS as agents. For this, we’re accessing the group “otrsagent” within our “Groups”-OU and lookig up the memberUids.
At last but not least, the actual LDAP parameters like the port for example.

Now, you can test your login by browsing to your index.pl and enter the credentials of an LDAP-user being in your otrsagent-group. You should now be possible to authenticate. Nothing more. You won’t be able to login to your OTRS yet. Why? It’s simple: OTRS uses LDAP only for authentication but initially copies the user-data from LDAP into its own database backend. Therefor we need to set up the “AuthSyncModule”.

This module allows us to tell OTRS that we’d like to have our user data being synchronized with the LDAP database. Let’s take a look at the actual configuration:

    $Self->{'AuthSyncModule'} = 'Kernel::System::Auth::Sync::LDAP';
    $Self->{'AuthSyncModule::LDAP::Host'} = 'ldap://localhost/';
    $Self->{'AuthSyncModule::LDAP::BaseDN'} = 'dc=something, dc=com';
    $Self->{'AuthSyncModule::LDAP::UID'} = 'uid';
    $Self->{'AuthSyncModule::LDAP::UserAttr'} = 'UID';
    $Self->{'AuthSyncModule::LDAP::AccessAttr'} = 'memberUid';
    $Self->{'AuthSyncModule::LDAP::SearchUserDN'} = 'cn=admin,dc=something,dc=com';
    $Self->{'AuthSyncModule::LDAP::SearchUserPw'} = 'swordfish';

    $Self->{'AuthSyncModule::LDAP::UserSyncMap'} = {
        UserFirstname => 'givenName',
        UserLastname  => 'sn',
        UserEmail     => 'mail',
    };
    $Self->{'AuthSyncModule::LDAP::UserSyncInitialGroups'} = [
        'users',
    ];

Again, from top to bottom: We tell OTRS what LDAP host, what BaseDN, what UID/UserAttr/AccessAttr, what search user and what password to use. Then, we need to define what’s needed to be synchronized. Here, we only sync the most important data: First name, last name and e-mail. Note: Without the mail entry this won’t work!
After that, we define what OTRS-groups the user should initially be in.

Now you should be able to authenticate and login with your LDAP user. :)

Next, customer authentication.

The customer authentication needs to be configured separately and also starts with basic LDAP information:

    $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
    $Self->{'Customer::AuthModule::LDAP::Host'} = 'localhost';
    $Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'dc=something,dc=com';
    $Self->{'Customer::AuthModule::LDAP::UID'} = 'uid';
    $Self->{'Customer::AuthModule::LDAP::GroupDN'} = 'cn=otrscustomer,ou=Groups,dc=something,dc=com';
    $Self->{'Customer::AuthModule::LDAP::UserAttr'} = 'UID';
    $Self->{'Customer::AuthModule::LDAP::AccessAttr'} = 'memberUid';
    $Self->{'Customer::AuthModule::LDAP::SearchUserDN'} = 'cn=admin,dc=something,dc=com';
    $Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = 'swordfish';
    $Self->{'Customer::AuthModule::LDAP::Params'} = {
        port => 389,
        timeout => 120,
        async => 0,
        version => 3,
    };

I think I don’t need to comment this section once again. Next:

    $Self->{CustomerUser} = {
      Name => 'LDAP Datasource',
      Module => 'Kernel::System::CustomerUser::LDAP',
      Params => {
         Host => 'localhost',
         BaseDN => 'dc=something,dc=com',
         SSCOPE => 'sub',
         UserDN => 'cn=admin,dc=something,dc=com',
         UserPW => 'swordfish',
         Params => {
            port => 389,
            timeout => 120,
            async => 0,
            version => 3,
         },
      },
      CustomerKey => 'uid',
      CustomerID => 'mail',
      CustomerUserListFields => ['sn', 'cn', 'mail'],
      CustomerUserSearchFields => ['uid', 'cn', 'sn', 'mail'],
CustomerUserSearchPrefix => '',
       CustomerUserSearchSuffix => '*',
       CustomerUserSearchListLimit => 250,
       CustomerUserPostMasterSearchFields => ['mail'],
       CustomerUserNameFields => ['givenname', 'sn'],
       CustomerUserExcludePrimaryCustomerID => 0,
       AdminSetPreferences => 0,
       Map => [
           [ 'UserSalutation', 'Title',      'title',           1, 0, 'var', '', 0 ],
           [ 'UserFirstname',  'Firstname',  'cn',              1, 1, 'var', '', 0 ],
           [ 'UserLastname',   'Lastname',   'sn',              1, 1, 'var', '', 0 ],
           [ 'UserLogin',      'Username',   'uid',             1, 1, 'var', '', 0 ],
           [ 'UserEmail',      'Email',      'mail',            1, 1, 'var', '', 0 ],
           [ 'UserCustomerID', 'CustomerID', 'mail',            0, 1, 'var', '', 0 ],
           [ 'UserPhone',      'Phone',      'telephonenumber', 1, 0, 'var', '', 0 ],
           [ 'UserAddress',    'Address',    'postaladdress',   1, 0, 'var', '', 0 ],
           [ 'UserComment',    'Comment',    'description',     1, 0, 'var', '', 0 ],
       ],
    };

This is theoretically the same we’ve also set up for the agents and will let OTRS synchronize the customer data into its own database. I think the whole mapping should be pretty clear when read carefully, so I’m not going to explain every setting in detail.

However, after you’ve hacked together your basic configuration in this kinda way, also the customer.pl authentication should be working against your LDAP.

There’s one more thing that’s left to be mentioned. When you authenticate your agents against the LDAP, OTRS will try to authenticate root@localhost against it – what probably won’t work anymore then. Of course, you won’t need to go without an administrative user now. Simply pick one of your LDAP users, add him to the otrsagent group, log in to the web-interface and then adding an entry into the group_user table of OTRS’ database, containing the user_id of your LDAP user (get it from the “users” table) and the group_id “1″, with the permission_key “rw” and the permission_value “1″. After that, the user should have administrative rights.

And the next time, I’ll show you how to build an automatic back-scratcher using a wall, some glue and a cat. Enjoy! :)

  1. Dima says:

    To add new otrs admin users group_id should be == “2″.
    insert into group_user(user_id, group_id, permission_key, permission_value) values(2,2,’rw’,1);
    OTRS ver. 2.4

  2. vikram says:

    thanks buddy i never worked with ldap and otrs just studied in few days and implement this in one day worked like charm after manipulating few entries as per my requirement thank you very much

  3. Marius M. says:

    Hey there,

    Dima, thank you for the hint! vikram, I’m glad my posting helped you, thanks. :)

    Best regards!

  4. Ray S. says:

    I am also new to LDAP, in the script that you provided do I need to replace all the ‘uid’ with a windows domain account?

  5. Ajeesh says:

    No need to replace the uid with username.
    uid is the stanadrd method to search for the user id in ldap

  6. chris says:

    Hi,I have something wrong with the otrs ldap:in admin account,customers have synchronized from the ldap,but can’t logon at the customer.pl,it says:”Login failed! Your user name or password was entered incorrectly.”can you help me?
    my scripts are below:

    #Enable LDAP authentication for Customers / Users
    $Self->{‘Customer::AuthModule’} = ‘Kernel::System::CustomerAuth::LDAP’;
    $Self->{‘Customer::AuthModule::LDAP::Host’} = ’10.10.17.2′;
    $Self->{‘Customer::AuthModule::LDAP::BaseDN’} = ‘ou=test,dc=jbnz,dc=com’;
    $Self->{‘Customer::AuthModule::LDAP::UID’} = ‘sAMAccountName’;

    # Check if the user is allowed to auth in a posixGroup
    # (e. g. user needs to be in a group OTRS_Agents to use otrs)
    $Self->{‘AuthModule::LDAP::GroupDN’} = ‘cn=test,ou=test,dc=jbnz,dc=com’;
    $Self->{‘AuthModule::LDAP::AccessAttr’} = ‘member’;
    $Self->{‘AuthModule::LDAP::UserAttr’} = ‘DN’;

    #The following is valid but would only be necessary if the
    #anonymous user do NOT have permission to read from the LDAP tree
    # $Self->{‘Customer::AuthModule::LDAP::SearchUserDN’} = ‘ou=test,dc=jbnz.com,dc=com’;
    #$Self->{‘Customer::AuthModule::LDAP::SearchUserPw’} = ‘searcherpassword’;

    #CustomerUser
    #(customer user database backend and settings)
    $Self->{CustomerUser} = {
    Module => ‘Kernel::System::CustomerUser::LDAP’,
    Params => {
    Host => ’10.10.17.2′,
    BaseDN => ‘ou=test,DC=jbnz,DC=com’,
    SSCOPE => ‘sub’,
    UserDN =>’test’,
    UserPw => ‘jbtest’,
    },
    # customer unique id
    CustomerKey => ‘sAMAccountName’,
    # customer #
    CustomerID => ‘mail’,
    CustomerUserListFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserSearchFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserSearchPrefix => ”,
    CustomerUserSearchSuffix => ‘*’,
    CustomerUserSearchListLimit => 250,
    CustomerUserPostMasterSearchFields => ['mail'],
    CustomerUserNameFields => ['givenname', 'sn'],
    Map => [
    # note: Login, Email and CustomerID needed!
    # var, frontend, storage, shown, required, storage-type
    #[ 'UserSalutation', 'Title', 'title', 1, 0, 'var' ],
    [ 'UserFirstname', 'Firstname', 'givenname', 1, 1, 'var' ],
    [ 'UserLastname', 'Lastname', 'sn', 1, 1, 'var' ],
    [ 'UserLogin', 'Login', 'sAMAccountName', 1, 1, 'var' ],
    [ 'UserEmail', 'Email', 'mail', 1, 1, 'var' ],
    [ 'UserCustomerID', 'CustomerID', 'mail', 0, 1, 'var' ],
    [ 'UserPhone', 'Phone', 'telephonenumber', 1, 0, 'var' ],
    #[ 'UserAddress', 'Address', 'postaladdress', 1, 0, 'var' ],
    #[ 'UserComment', 'Comment', 'description', 1, 0, 'var' ],
    ],
    };

    #Add the following lines when only users are allowed to login if they reside in the spicified security group
    #Remove these lines if you want to provide login to all users specified in the User Base DN
    #example: $Self->{‘Customer::AuthModule::LDAP::BaseDN’} = ‘ou=BaseOU, dc=example, dc=com’;
    $Self->{‘Customer::AuthModule::LDAP::GroupDN’} = ‘CN=test,ou=test,DC=jbnz,DC=com’;
    $Self->{‘Customer::AuthModule::LDAP::AccessAttr’} = ‘member’;
    $Self->{‘Customer::AuthModule::LDAP::UserAttr’} = ‘DN’

  7. Tom Yerex says:

    If the authentication is left out for the customers, will OTRS step in and provide the customer password if the customer uses the lost password recovery process?

    Our LDAP directory does not provide any authentication details, it only provides contact details, so I am hoping that OTRS will provide support for a password.

Have your say.

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>