OTRS: Установка на Ubuntu, аутентификация в Active Directory и Single sign on

// Август 13th, 2014 // Системное администрирование

otrs-iconВ этой статье я опишу опыт установки helpdesk системы OTRS. Первоначально для себя надо ответить на вопрос, а зачем же вам нужна helpdesk система? Может быть хватит обычной тикет-системы, или какого-либо онлайн сервиса. При выборе helpdesk системы я, в первую очередь, руководствовался не обширным набором функций, а успешным опытом развертывания данной системы в различных организациях. 

Требования

Для начала определимся с требованиями. Допустим у нас уже есть центральный сервер, с развернутой на нём службой каталогов (Active Directory). Необходимо сделать так, чтобы пользователи могли авторизовываться в системе, создавать заявки, а технические специалисты отвечать на них и собственно выполнять. Для этих целей поставим виртуальную машину и развернём на ней OTRS.

Установка OTRS

В начале своих изысканий я наткнулся на такую замечательную вещь, как OTRS Appliance. Это готовый ISO-образ (скачать версию 3.3.7), который можно подключить к виртуальной машине как CD-ROM и автоматически установить OTRS. Это вселяло надежду на скорое решение проблемы, но моя радость была бы не полной. если бы не некоторые грабли. В частности часть системы вынесена в отдельный RAM диск и после установки пакетов (например mc) они живут ровно до перезагрузки. Естественно это было неприемлемо и я решил установить OTRS вручную на чистую Ubuntu 14.04.

Качаем исходники и распаковываем их в каталог /opt/otrs-3.3.7

wget http://ftp.otrs.org/pub/otrs/otrs-3.3.7.tar.gz
tar zxf ./otrs-3.3.7.tar.gz
mv ./otrs-3.3.7 /opt
ln /opt/otrs-3.3.7 /opt/otrs

Теперь устанавливаем необходимые пакеты:

apt-get install libapache2-mod-perl2 libdbd-mysql-perl libnet-dns-perl libnet-ldap-perl libio-socket-ssl-perl libpdf-api2-perl libsoap-lite-perl libgd-text-perl libgd-graph-perl libapache-dbi-perl libyaml-libyaml-perl mysql-server

Далее проверяем все ли модули Perl мы поставили этой командой:

perl /opt/otrs/bin/otrs.CheckModules.pl

Если каких-то модулей нет, и они необходимы — то ставим их примерно так

sudo apt-get install libJSON-XS-perl
sudo apt-get install libtext-csv-perl

или так

perl -MCPAN -e shell
cpan> install DBD::Pg

Создаём пользователя для Otrs

sudo useradd -r -d /opt/otrs/ -c 'OTRS user' otrs
sudo usermod -g www-data otrs

Если файлов конфигов (не .dist а именно .pm) нет, то копируем их из файлов дистрибьютива:

cd /opt/otrs/Kernel
sudo cp Config.pm.dist Config.pm
sudo cp Config/GenericAgent.pm.dist Config/GenericAgent.pm

Настраиваем права под свежесозданного пользователя:

cd /opt/otrs
sudo bin/otrs.SetPermissions.pl --otrs-user=otrs \
--otrs-group=otrs --web-user=www-data \
--web-group=www-data /opt/otrs

Дальше создаём vhost для Апача (который у нас должен уже стоять кстати):

sudo cp /opt/otrs/scripts/apache2-httpd.include.conf \
/etc/apache2/sites-avaliable/otrs.conf

У меня он получился в результате вот такой (я не менял его).

# --
# added for OTRS (http://otrs.org/)
# --

ScriptAlias /otrs/ "/opt/otrs/bin/cgi-bin/"
Alias /otrs-web/ "/opt/otrs/var/httpd/htdocs/"

# activate this if you are using an Oracle database
#SetEnv ORACLE_HOME /path/to/your/oracle/
#SetEnv ORACLE_SID YOUR_SID
#SetEnv NLS_LANG AMERICAN_AMERICA.UTF8
#SetEnv NLS_DATE_FORMAT 'YYYY-MM-DD HH24:MI:SS'

    # Setup environment and preload modules
    Perlrequire /opt/otrs/scripts/apache2-perl-startup.pl

    # Reload Perl modules when changed on disk
    PerlModule Apache2::Reload
    PerlInitHandler Apache2::Reload

    # general mod_perl2 options

#        ErrorDocument 403 /otrs/customer.pl
        ErrorDocument 403 /otrs/index.pl
        SetHandler  perl-script
        PerlResponseHandler ModPerl::Registry
        Options +ExecCGI
        PerlOptions +ParseHeaders
        PerlOptions +SetupEnv

                Order allow,deny
                Allow from all

            = 2.4>
                Require all granted

            Order allow,deny
            Allow from all

    # mod_perl2 options for GenericInterface

        PerlOptions -ParseHeaders

<Directory "/opt/otrs/bin/cgi-bin/">
    AllowOverride All
    Options +ExecCGI -Includes

            Order allow,deny
            Allow from all

        = 2.4>
            Require all granted

        Order allow,deny
        Allow from all

        AddOutputFilterByType DEFLATE text/html text/javascript text/css text/xml application/json text/json

<Directory "/opt/otrs/var/httpd/htdocs/">
    AllowOverride All

            Order allow,deny
            Allow from all

        = 2.4>
            Require all granted

        Order allow,deny
        Allow from all

        AddOutputFilterByType DEFLATE text/html text/javascript text/css text/xml application/json text/json

    # Make sure CSS and JS files are read as UTF8 by the browsers.
    AddCharset UTF-8 .css
    AddCharset UTF-8 .js

    # Set explicit mime type for woff fonts since it is relatively new and apache may not know about it.
    AddType application/font-woff .woff

    # Cache css-cache for 30 days
    <Directory "/opt/otrs/var/httpd/htdocs/skins/*/*/css-cache">
        <FilesMatch "\.(css|CSS)$">
            Header set Cache-Control "max-age=2592000 must-revalidate"

    # Cache css thirdparty for 4 hours, including icon fonts
    <Directory "/opt/otrs/var/httpd/htdocs/skins/*/*/css/thirdparty">
        <FilesMatch "\.(css|CSS|woff|svg)$">
            Header set Cache-Control "max-age=14400 must-revalidate"

    # Cache js-cache for 30 days
    <Directory "/opt/otrs/var/httpd/htdocs/js/js-cache">
        <FilesMatch "\.(js|JS)$">
            Header set Cache-Control "max-age=2592000 must-revalidate"

    # Cache js thirdparty for 4 hours
    <Directory "/opt/otrs/var/httpd/htdocs/js/thirdparty/">
        <FilesMatch "\.(js|JS)$">
            Header set Cache-Control "max-age=14400 must-revalidate"

# Limit the number of requests per child to avoid excessive memory usage
MaxRequestsPerChild 4000

Теперь включаем этот vhost. Эта команда создаёт симлинк в папке sites-enable. После этого можем перезагрузить апач.

sudo a2ensite otrs
sudo service apache2 restart

После этого можно открыть в браузере установочный скрипт (http://your_otrs_ip_adress/otrs/installer.pl) и следую ему завершить установку otrs.

otrs_installer

Настройка авторизации пользователей в Active Directory

Как правило, в компаниях существует сервер (контроллер домена) в котором хранится база всех пользователей, и желательно сделать так, чтобы наши родные пользователи смогли проходить аутентификацию со своим AD-аккаунтом в OTRS. Это можно сделать так.

Требования к аккаунтам
У пользователей в AD должно быть заполнено поля с информацией об имени (Имя. Фамилия, Отчество (инициал) и email). Без этого они не пройдёт аутентификацию.

Итак, заходим в админку (http://otrs-server.domain/otrs/index.pl) с аккаунтом локального администратора (кroot@localhost / root). Далее необходимо произвести базовую настройку.
Заходим «Администрирование» -> «Конфигурация системы». В выпадающем списке слева выбираем «Framework» и в появившемся списке справа выбираем «Frontend::Customer»:

otrs-new-customer-settings

на CustomerPanelCreateAccount указываем «Нет» и жмем внизу кнопку «Обновить».

Сквозная авторизация (SSO)

Для работы в OTRS пользователь должен быть авторизован, т.е. системе должен быть известен ID пользователя. Обычно таким ID выступает логин. Стандартно пользователю предлагается ввести логин и пароль в форме авторизации. Используя Authentication backends, OTRS может выполнить авторизацию пользователя.

Если предположить, что при открытии страницы OTRS пользователь уже известен, то повторно запрашивать авторизацию не надо. Т.к. в моем случае все пользователи уже авторизованы в домене Windows, логично это как-то использовать. Таким образом, нужно данные авторизации передать в OTRS.

Алгоритм авторизации

1. Пользователь включает компьютер, авторизуется в домене с помощью Kerberos. В Kerberos контроллер домена именуется центром распространения ключей Key Distribution Center (KDC). На высоком уровне это выглядит так: при регистрации пользователя на компьютере формируется серия обменов данными с контроллером домена (DC), и в случае успеха пользователю назначается билет на право получения билетов (TGT). Впоследствии при каждом обращении к службе, такой как общая папка или приложение, TGT используется, чтобы получить билет для доступа к службе или приложению.
2. С TGT пользователь обращается браузером (тестировалось под Internet Explorer) к веб-серверу (Apache2). Для того, чтобы бразер отдавал веб-серверу TGT нужно сделать соответствующую настройку клиента.

  • Кликнуть по иконки с шестеренкой -> Свойства браузера -> Безопасность -> Местная интросеть -> Кнопка «Сайты» -> Кнопка «Дополнительно»
  • Заполнить поле «Добавить в зону следующий узел»: http://helpdesk.domain.ru Нажать на кнопки «Добавить», «Закрыть», «Ok», «Ok».

3. Там модуль Апача mod_auth_kerb получает от браузера билет TGT и обращается с ним к KDC (он же контроллер домена). При этом сам хост с апачем должен быть введен в домен и на быть принципиалом Kerberos чтобы осуществить это обращение.

Чтобы работал этот этап нужно сделать две вещи. Во-первых в дефолтном конфиге vhost-а для otrs разрешить использовать файлы .htaccess вот так (зменить None на All):

<Directory "/opt/otrs/bin/cgi-bin/">
    AllowOverride All

и собственно разместить файл .htaccess

/opt/otrs/bin/cgi-bin/.htaccess

AuthType Kerberos
KrbAuthRealms DOMAIN.RU
KrbMethodNegotiate On
KrbMethodK5Passwd On
KrbServiceName HTTP/helpdesk.domain.ru
Krb5KeyTab /etc/krb5.keytab
require valid-user

Файл krb5.keytab нужно будет сгенерировать на контроллере домена, ниже я напишу об этом в разделе «Ввод веб-сервера в домен».

4. KDС выдаёт Апачу билет для доступа к службе, из которого апач выдергивает имя пользователя в формате username@domain.ru и помещает его в переменную окружения $ENV[‘REMOTE_USER’].

5. OTRS с помощью модуля авторизации Auth:Customer:ADSSO принимает результаты прохождения BasicAuth как успешную авторизацию и забирает имя пользователя из $ENV[‘REMOTE_USER’]

6. Пользователь видит панель OTRS в залогиненном виде. Если в переменной окружения нет имени пользователя, то всплывает окно авторищации, в котором пользователь вводит свой логин и пароль.

Устанавливаем необходимые пакеты

Готовим систему

Систему будем ставить на хост helpdesk.domain.ru (внешний IP = x.x.x.x, внутренний IP = y.y.y.y).

Ставим пакеты для Kerberos и Samba

sudo apt-get install samba samba-common samba-common-bin krb5-config krb5-multidev krb5-user libgssapi-krb5-2 libkrb5-3 libkrb5-dev libkrb5support0 winbind ntp libapache2-mod-auth-kerb

/etc/hostname
Прописываем имя машины. Желательно капсом. Так точно работает.

HELPDESK

/etc/hosts

127.0.0.1	localhost
y.y.y.y	HELPDESK.domain.ru	HELPDESK

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

где y.y.y.y — внутренний IP адрес вашего контроллера домена

/etc/resolv.conf

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver x.x.x.x
search domain.ru

где x.x.x.x — внешний IP адрес вашего контроллера домена

Конфиги для LDAP-Auth + SSO

Теперь меняем конфиги до такого вида. Я приведу конфиги, который сразу обеспечивает авто-логин или сквозную авторизацию

/etc/krb5.conf

[libdefaults]
	default_realm = domain.RU

# The following krb5.conf variables are only for MIT Kerberos.
	krb4_config = /etc/krb.conf
	krb4_realms = /etc/krb.realms
	kdc_timesync = 1
	ccache_type = 4
	forwardable = true
	proxiable = true

# The following encryption type specification will be used by MIT Kerberos
# if uncommented.  In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# Thie only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).

#	default_tgs_enctypes = des3-hmac-sha1
#	default_tkt_enctypes = des3-hmac-sha1
#	permitted_enctypes = des3-hmac-sha1

# The following libdefaults parameters are only for Heimdal Kerberos.
	v4_instance_resolve = false
	v4_name_convert = {
		host = {
			rcmd = host
			ftp = ftp
		}
		plain = {
			something = something-else
		}
	}
	fcc-mit-ticketflags = true

[realms]
	ATHENA.MIT.EDU = {
		kdc = kerberos.mit.edu:88
		kdc = kerberos-1.mit.edu:88
		kdc = kerberos-2.mit.edu:88
		admin_server = kerberos.mit.edu
		default_domain = mit.edu
	}
	MEDIA-LAB.MIT.EDU = {
		kdc = kerberos.media.mit.edu
		admin_server = kerberos.media.mit.edu
	}
	ZONE.MIT.EDU = {
		kdc = casio.mit.edu
		kdc = seiko.mit.edu
		admin_server = casio.mit.edu
	}
	MOOF.MIT.EDU = {
		kdc = three-headed-dogcow.mit.edu:88
		kdc = three-headed-dogcow-1.mit.edu:88
		admin_server = three-headed-dogcow.mit.edu
	}
	CSAIL.MIT.EDU = {
		kdc = kerberos-1.csail.mit.edu
		kdc = kerberos-2.csail.mit.edu
		admin_server = kerberos.csail.mit.edu
		default_domain = csail.mit.edu
		krb524_server = krb524.csail.mit.edu
	}
	IHTFP.ORG = {
		kdc = kerberos.ihtfp.org
		admin_server = kerberos.ihtfp.org
	}
	GNU.ORG = {
		kdc = kerberos.gnu.org
		kdc = kerberos-2.gnu.org
		kdc = kerberos-3.gnu.org
		admin_server = kerberos.gnu.org
	}
	1TS.ORG = {
		kdc = kerberos.1ts.org
		admin_server = kerberos.1ts.org
	}
	GRATUITOUS.ORG = {
		kdc = kerberos.gratuitous.org
		admin_server = kerberos.gratuitous.org
	}
	DOOMCOM.ORG = {
		kdc = kerberos.doomcom.org
		admin_server = kerberos.doomcom.org
	}
	ANDREW.CMU.EDU = {
		kdc = kerberos.andrew.cmu.edu
		kdc = kerberos2.andrew.cmu.edu
		kdc = kerberos3.andrew.cmu.edu
		admin_server = kerberos.andrew.cmu.edu
		default_domain = andrew.cmu.edu
	}
	CS.CMU.EDU = {
		kdc = kerberos.cs.cmu.edu
		kdc = kerberos-2.srv.cs.cmu.edu
		admin_server = kerberos.cs.cmu.edu
	}
	DEMENTIA.ORG = {
		kdc = kerberos.dementix.org
		kdc = kerberos2.dementix.org
		admin_server = kerberos.dementix.org
	}
	stanford.edu = {
		kdc = krb5auth1.stanford.edu
		kdc = krb5auth2.stanford.edu
		kdc = krb5auth3.stanford.edu
		master_kdc = krb5auth1.stanford.edu
		admin_server = krb5-admin.stanford.edu
		default_domain = stanford.edu
	}
        UTORONTO.CA = {
                kdc = kerberos1.utoronto.ca
                kdc = kerberos2.utoronto.ca
                kdc = kerberos3.utoronto.ca
                admin_server = kerberos1.utoronto.ca
                default_domain = utoronto.ca
	}
	DOMAIN.RU = {
	    kdc = DOMAIN-SERV2.DOMAIN.RU
	    master_kdc = DOMAIN-SERV2.DOMAIN.RU
	    admin_server = DOMAIN-SERV2.DOMAIN.RU
	    default_domain = DOMAIN.RU
	}

[domain_realm]
	.mit.edu = ATHENA.MIT.EDU
	mit.edu = ATHENA.MIT.EDU
	.media.mit.edu = MEDIA-LAB.MIT.EDU
	media.mit.edu = MEDIA-LAB.MIT.EDU
	.csail.mit.edu = CSAIL.MIT.EDU
	csail.mit.edu = CSAIL.MIT.EDU
	.whoi.edu = ATHENA.MIT.EDU
	whoi.edu = ATHENA.MIT.EDU
	.stanford.edu = stanford.edu
	.slac.stanford.edu = SLAC.STANFORD.EDU
        .toronto.edu = UTORONTO.CA
        .utoronto.ca = UTORONTO.CA
	domain.ru = DOMAIN.RU
	.domain.ru = DOMAIN.RU
[login]
	krb4_convert = true
	krb4_get_tickets = false

/etc/samba/smb.conf — см начало секции [global]

#
# Sample configuration file for the Samba suite for Debian GNU/Linux.
#
#
# This is the main Samba configuration file. You should read the
# smb.conf(5) manual page in order to understand the options listed
# here. Samba has a huge number of configurable options most of which 
# are not shown in this example
#
# Some options that are often worth tuning have been included as
# commented-out examples in this file.
#  - When such options are commented with ";", the proposed setting
#    differs from the default Samba behaviour
#  - When commented with "#", the proposed setting is the default
#    behaviour of Samba but the option is considered important
#    enough to be mentioned here
#
# NOTE: Whenever you modify this file you should run the command
# "testparm" to check that you have not made any basic syntactic 
# errors. 

#======================= Global Settings =======================

[global]
workgroup = DOMAIN
realm = DOMAIN.RU
netbios name = HELPDESK
security = ADS
idmap uid = 10000-20000
idmap gid = 10000-20000
winbind enum users = yes
winbind enum groups = yes
winbind use default domain = yes
machine password timeout = 0 # needed when using only the machine account as described below

## Browsing/Identification ###

# Change this to the workgroup/NT-domain name your Samba server will part of
#   workgroup = WORKGROUP

# server string is the equivalent of the NT Description field
	server string = %h server (Samba, Ubuntu)

# Windows Internet Name Serving Support Section:
# WINS Support - Tells the NMBD component of Samba to enable its WINS Server
#   wins support = no

# WINS Server - Tells the NMBD components of Samba to be a WINS Client
# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
;   wins server = w.x.y.z

# This will prevent nmbd to search for NetBIOS names through DNS.
   dns proxy = no

#### Networking ####

# The specific set of interfaces / networks to bind to
# This can be either the interface name or an IP address/netmask;
# interface names are normally preferred
;   interfaces = 127.0.0.0/8 eth0

# Only bind to the named interfaces and/or networks; you must use the
# 'interfaces' option above to use this.
# It is recommended that you enable this feature if your Samba machine is
# not protected by a firewall or is a firewall itself.  However, this
# option cannot handle dynamic or non-broadcast interfaces correctly.
;   bind interfaces only = yes

#### Debugging/Accounting ####

# This tells Samba to use a separate log file for each machine
# that connects
   log file = /var/log/samba/log.%m

# Cap the size of the individual log files (in KiB).
   max log size = 1000

# If you want Samba to only log through syslog then set the following
# parameter to 'yes'.
#   syslog only = no

# We want Samba to log a minimum amount of information to syslog. Everything
# should go to /var/log/samba/log.{smbd,nmbd} instead. If you want to log
# through syslog you should set the following parameter to something higher.
   syslog = 0

# Do something sensible when Samba crashes: mail the admin a backtrace
   panic action = /usr/share/samba/panic-action %d

####### Authentication #######

# Server role. Defines in which mode Samba will operate. Possible
# values are "standalone server", "member server", "classic primary
# domain controller", "classic backup domain controller", "active
# directory domain controller". 
#
# Most people will want "standalone sever" or "member server".
# Running as "active directory domain controller" will require first
# running "samba-tool domain provision" to wipe databases and create a
# new domain.
   server role = standalone server

# If you are using encrypted passwords, Samba will need to know what
# password database type you are using.  
   passdb backend = tdbsam

   obey pam restrictions = yes

# This boolean parameter controls whether Samba attempts to sync the Unix
# password with the SMB password when the encrypted SMB password in the
# passdb is changed.
   unix password sync = yes

# For Unix password sync to work on a Debian GNU/Linux system, the following
# parameters must be set (thanks to Ian Kahan <<kahan@informatik.tu-muenchen.de> for
# sending the correct chat script for the passwd program in Debian Sarge).
   passwd program = /usr/bin/passwd %u
   passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .

# This boolean controls whether PAM will be used for password changes
# when requested by an SMB client instead of the program listed in
# 'passwd program'. The default is 'no'.
   pam password change = yes

# This option controls how unsuccessful authentication attempts are mapped
# to anonymous connections
   map to guest = bad user

########## Domains ###########

#
# The following settings only takes effect if 'server role = primary
# classic domain controller', 'server role = backup domain controller'
# or 'domain logons' is set 
#

# It specifies the location of the user's
# profile directory from the client point of view) The following
# required a [profiles] share to be setup on the samba server (see
# below)
;   logon path = \\%N\profiles\%U
# Another common choice is storing the profile in the user's home directory
# (this is Samba's default)
#   logon path = \\%N\%U\profile

# The following setting only takes effect if 'domain logons' is set
# It specifies the location of a user's home directory (from the client
# point of view)
;   logon drive = H:
#   logon home = \\%N\%U

# The following setting only takes effect if 'domain logons' is set
# It specifies the script to run during logon. The script must be stored
# in the [netlogon] share
# NOTE: Must be store in 'DOS' file format convention
;   logon script = logon.cmd

# This allows Unix users to be created on the domain controller via the SAMR
# RPC pipe.  The example command creates a user account with a disabled Unix
# password; please adapt to your needs
; add user script = /usr/sbin/adduser --quiet --disabled-password --gecos "" %u

# This allows machine accounts to be created on the domain controller via the 
# SAMR RPC pipe.  
# The following assumes a "machines" group exists on the system
; add machine script  = /usr/sbin/useradd -g machines -c "%u machine account" -d /var/lib/samba -s /bin/false %u

# This allows Unix groups to be created on the domain controller via the SAMR
# RPC pipe.  
; add group script = /usr/sbin/addgroup --force-badname %g

############ Misc ############

# Using the following line enables you to customise your configuration
# on a per machine basis. The %m gets replaced with the netbios name
# of the machine that is connecting
;   include = /home/samba/etc/smb.conf.%m

# Some defaults for winbind (make sure you're not using the ranges
# for something else.)
;   idmap uid = 10000-20000
;   idmap gid = 10000-20000
;   template shell = /bin/bash

# Setup usershare options to enable non-root users to share folders
# with the net usershare command.

# Maximum number of usershare. 0 (default) means that usershare is disabled.
;   usershare max shares = 100

# Allow users who've been granted usershare privileges to create
# public shares, not just authenticated ones
   usershare allow guests = yes

#======================= Share Definitions =======================

# Un-comment the following (and tweak the other settings below to suit)
# to enable the default home directory shares. This will share each
# user's home directory as \\server\username
;[homes]
;   comment = Home Directories
;   browseable = no

# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
;   read only = yes

# File creation mask is set to 0700 for security reasons. If you want to
# create files with group=rw permissions, set next parameter to 0775.
;   create mask = 0700

# Directory creation mask is set to 0700 for security reasons. If you want to
# create dirs. with group=rw permissions, set next parameter to 0775.
;   directory mask = 0700

# By default, \\server\username shares can be connected to by anyone
# with access to the samba server.
# Un-comment the following parameter to make sure that only "username"
# can connect to \\server\username
# This might need tweaking when using external authentication schemes
;   valid users = %S

# Un-comment the following and create the netlogon directory for Domain Logons
# (you need to configure Samba to act as a domain controller too.)
;[netlogon]
;   comment = Network Logon Service
;   path = /home/samba/netlogon
;   guest ok = yes
;   read only = yes

# Un-comment the following and create the profiles directory to store
# users profiles (see the "logon path" option above)
# (you need to configure Samba to act as a domain controller too.)
# The path below should be writable by all users so that their
# profile directory may be created the first time they log on
;[profiles]
;   comment = Users profiles
;   path = /home/samba/profiles
;   guest ok = no
;   browseable = no
;   create mask = 0600
;   directory mask = 0700

[printers]
   comment = All Printers
   browseable = no
   path = /var/spool/samba
   printable = yes
   guest ok = no
   read only = yes
   create mask = 0700

# Windows clients look for this share name as a source of downloadable
# printer drivers
[print$]
   comment = Printer Drivers
   path = /var/lib/samba/printers
   browseable = yes
   read only = yes
   guest ok = no
# Uncomment to allow remote administration of Windows print drivers.
# You may need to replace 'lpadmin' with the name of the group your
# admin users are members of.
# Please note that you also need to set appropriate Unix permissions
# to the drivers directory for these users to have write rights in it
;   write list = root, @lpadmin

Теперь настраиваем .htaccess
/opt/otrs/bin/cgi-bin/.htaccess
/opt/otrs/bin/cgi-bin/.htaccess

AuthType Kerberos
KrbAuthRealms DOMAIN.RU
KrbMethodNegotiate On
KrbMethodK5Passwd On
KrbServiceName HTTP/helpdesk.domain.ru
Krb5KeyTab /etc/krb5.keytab
require valid-user

Отлично, теперь вводим веб-сервер в домен.
Во-первых создаём юзера helpdesk в Active Directory.

Далее собственно вводим в домен сервер.

webserver:~# net ads join -U helpdesk
Enter administrator's password:
Using short domain name -- YOURDOMAIN
Joined 'HELPDESK' to realm 'domain.ru'

Перезапускаем службы

webserver:~# /etc/init.d/samba restart
Stopping Samba daemons: nmbd smbd.
Starting Samba daemons: nmbd smbd.
webserver:~# /etc/init.d/winbind restart
Stopping the Winbind daemon: winbind.
Starting the Winbind daemon: winbind.

Перезагружаем сервер

sudo shutdown -r now

Далее после загрузки сервер должен выдавать нам данные о домена при следующих запросах:

Запрос службы RPC

helpdesk:~# wbinfo -t
checking the trust secret for domain YOURDOMAIN via RPC calls succeeded

список юзеров

helpdesk:~# wbinfo -u
** тут будет список пользователей, если всё хорошо **

и групп

helpdesk:~# wbinfo -g
** тут будет список групп, если всё хорошо **

Идём на контроллер домена и генерируем там файл krb5.keytab

ktpass -princ HOST/helpdesk.domain.ru@DOMAIN.RU -mapuser helpdesk@DOMAIN.RU -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass Kerber0s -out c:\krb5.keytab
ktpass -princ HTTP/helpdesk.domain.ru@DOMAIN.RU -mapuser helpdesk@DOMAIN.RU -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass Kerber0s -out c:\krb5.keytab -in c:\krb5.keytab

Потом на веб-сервере кладём его в /etc/krb5.keytab и даём права апачу читать его

helpdesk:~# chown root.www-data /etc/krb5.keytab
helpdesk:~# chmod 0640 /etc/krb5.keytab

В дистрибьютиве OTRS есть файлик whoami.pl можно закинуть его в корень веб-сервера и тестировать там. Ну или смотреть с помоью того же phpinfo(); переменную окружения $ENV[‘REMOTE_USER’]

Перезагружаем Апач, на компьютере клиента авторизовываемся с помощью доменной учётки, ставим разрешение в IE авторизовываться автоматически, заходим на тестовый скрипт и если всё хорошо видим нашу учётку вида user@domain.ru в этой переменной.

Далее настраиваем OTRS на то, чтобы пользователи (Customers) могли авторизовываться автоматически.

Меняем конфиг.

/opt/otrs/Kernel/Config.pm

# --
# Kernel/Config.pm - Config file for OTRS kernel
# Copyright (C) 2001-2014 OTRS AG, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --
#  Note:
#
#  -->> Most OTRS configuration should be done via the OTRS web interface
#       and the SysConfig. Only for some configuration, such as database
#       credentials and customer data source changes, you should edit this
#       file. For changes do customer data sources you can copy the definitions
#       from Kernel/Config/Defaults.pm and paste them in this file.
#       Config.pm will not be overwritten when updating OTRS.
# --

package Kernel::Config;

use strict;
use warnings;
use utf8;

sub Load {
    my $Self = shift;

    # ---------------------------------------------------- #
    # database settings                                    #
    # ---------------------------------------------------- #

    # The database host
    $Self->{'DatabaseHost'} = '127.0.0.1';

    # The database name
    $Self->{'Database'} = "otrs";

    # The database user
    $Self->{'DatabaseUser'} = "otrs";

    # The password of database user. You also can use bin/otrs.CryptPassword.pl
    # for crypted passwords
    $Self->{'DatabasePw'} = '1wpyVmrXMy3fnB4U';

    # The database DSN for MySQL ==> more: "perldoc DBD::mysql"
    $Self->{'DatabaseDSN'} = "DBI:mysql:database=$Self->{Database};host=$Self->{DatabaseHost}";

    # The database DSN for PostgreSQL ==> more: "perldoc DBD::Pg"
    # if you want to use a local socket connection
#    $Self->{DatabaseDSN} = "DBI:Pg:dbname=$Self->{Database};";
    # if you want to use a TCP/IP connection
#    $Self->{DatabaseDSN} = "DBI:Pg:dbname=$Self->{Database};host=$Self->{DatabaseHost};";
    # if you have PostgresSQL 8.1 or earlier, activate the legacy driver with this line:
#    $Self->{DatabasePostgresqlBefore82} = 1;

    # The database DSN for Microsoft SQL Server - only supported if OTRS is
    # installed on Windows as well
#    $Self->{DatabaseDSN} = "DBI:ODBC:driver={SQL Server};Database=$Self->{Database};Server=$Self->{DatabaseHost},1433";

    # The database DSN for Oracle ==> more: "perldoc DBD::oracle"
#    $ENV{ORACLE_HOME} = '/u01/app/oracle/product/10.2.0/client_1';
#    $ENV{NLS_DATE_FORMAT} = 'YYYY-MM-DD HH24:MI:SS';
#    $ENV{NLS_LANG} = "american_america.utf8";

#    $Self->{DatabaseDSN} = "DBI:Oracle:sid=OTRS;host=$Self->{DatabaseHost};port=1522;";

    # ---------------------------------------------------- #
    # fs root directory
    # ---------------------------------------------------- #
    $Self->{Home} = '/opt/otrs';

    # ---------------------------------------------------- #
    # insert your own config settings "here"               #
    # config settings taken from Kernel/Config/Defaults.pm #
    # ---------------------------------------------------- #
    # $Self->{SessionUseCookie} = 0;
    # $Self->{CheckMXRecord} = 0;

# DOMAIN LDAP CONFIG START
$Self->{DefaultLanguage} = 'ru';
$Self->{UserLanguage} = 'ru';
# Enable LDAP Authentication Sync for Agent #
$Self->{'AuthSyncModule'} = 'Kernel::System::Auth::Sync::LDAP';
$Self->{'AuthSyncModule::LDAP::Host'} = '172.20.21.32';
$Self->{'AuthSyncModule::LDAP::BaseDN'} = 'dc=domain,dc=ru';
$Self->{'AuthSyncModule::LDAP::UID'} = 'sAMAccountName';
$Self->{'AuthSyncModule::LDAP::AccessAttr'} = 'member';
$Self->{'AuthSyncModule::LDAP::SearchUserDN'} = 'CN=helpdesk,CN=Users,DC=domain,DC=ru';
$Self->{'AuthSyncModule::LDAP::SearchUserPw'} = 'helpdesk-ad-account-password';

# Enable Agent Mapping from LDAP to DB #
$Self->{'AuthSyncModule::LDAP::UserSyncMap'} = {
    UserFirstname => 'givenName',
    UserLastname => 'sn',
    UserEmail => 'mail',
};

$Self->{'AuthSyncModule::LDAP::UserSyncInitialGroups'} = [
    'users',
    ];
$Self->{'AuthModule'} = 'Kernel::System::Auth::LDAP';
$Self->{'AuthModule::LDAP::Host'} = '172.20.21.32';
$Self->{'AuthModule::LDAP::BaseDN'} = 'dc=doman,dc=ru';
$Self->{'AuthModule::LDAP::UID'} = 'sAMAccountName';
$Self->{'AuthModule::LDAP::SearchUserDN'} = 'CN=helpdesk,CN=Users,DC=domain,DC=ru';
$Self->{'AuthModule::LDAP::SearchUserPw'} = 'helpdesk-ad-account-password';
$Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::ADSSO'; #LDAP
$Self->{'Customer::AuthModule::LDAP::Host'} ='172.20.21.32';
$Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'dc=domain,dc=ru';
$Self->{'Customer::AuthModule::LDAP::UID'} = 'sAMAccountName';
$Self->{'Customer::AuthModule::LDAP::SearchUserDN'} = 'CN=helpdesk,CN=Users,DC=domain,DC=ru';
$Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = 'helpdesk-ad-account-password';

# $Self->{'AuthModule'} = 'Kernel::System::Auth::HTTPBasicAuth';

$Self->{CustomerUser} = {
  Module => 'Kernel::System::CustomerUser::LDAP',
  Params => {
     Host => '172.20.21.32',
     BaseDN => 'dc=domain,dc=ru',
     SSCOPE => 'sub',
     UserDN => 'CN=helpdesk,CN=Users,DC=domain,DC=ru',
     UserPw => 'helpdesk-ad-account-password',
 },
 CustomerKey => 'sAMAccountName',
 CustomerID => 'mail',
 CustomerUserListFields => ['sAMAccountName', 'cn', 'mail'],
 CustomerUserSearchFields => ['sAMAccountName', 'cn', 'mail'],
 CustomerUserPostMasterSearchFields => ['mail'],
 CustomerUserNameFields => ['givenname', 'sn'],
 Map => [
   [ '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' ],
 ],
};

# DOMAIN LDAP Config End

    # ---------------------------------------------------- #

    # ---------------------------------------------------- #
    # data inserted by installer                           #
    # ---------------------------------------------------- #
    # $DIBI$

    # ---------------------------------------------------- #
    # ---------------------------------------------------- #
    #                                                      #
    # end of your own config options!!!                    #
    #                                                      #
    # ---------------------------------------------------- #
    # ---------------------------------------------------- #
}

# ---------------------------------------------------- #
# needed system stuff (don't edit this)                #
# ---------------------------------------------------- #

use base qw(Kernel::Config::Defaults);

# -----------------------------------------------------#

1;

И добавляем файл адаптера авторизации.

/opt/otrs/Kernel/System/CustomerAuth/ADSSO.pm — это модифицированный вариант предлагаемого файла отсюда.

# --
# Kernel/System/CustomerAuth/ADSSO.pm - provides the ldap authentication
# Copyright (C) 2001-2010 OTRS AG, http://otrs.org/
# --
# $Id: LDAP.pm,v 1.33.2.2 2010/01/05 16:10:49 martin Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

###################################################################
### Change by Igor Revyakin
### change begin

###package Kernel::System::CustomerAuth::LDAP;
package Kernel::System::CustomerAuth::ADSSO;

### change end
###################################################################

use strict;
use warnings;

use Net::LDAP;

use vars qw($VERSION);
$VERSION = qw($Revision: 1.33.2.2 $) [1];

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {};
    bless( $Self, $Type );

    # check needed objects
    for (qw(LogObject ConfigObject DBObject EncodeObject)) {
        $Self->{$_} = $Param{$_} || die "No $_!";
    }

    # Debug 0=off 1=on
    $Self->{Debug} = 0;

    # get ldap preferences
    $Self->{Die} = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Die' . $Param{Count} );
    if ( $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Host' . $Param{Count} ) ) {
        $Self->{Host}
            = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Host' . $Param{Count} );
    }
    else {
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => "Need Customer::AuthModule::LDAPHost$Param{Count} in Kernel/Config.pm",
        );
        return;
    }
    if (
        defined(
            $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::BaseDN' . $Param{Count} )
        )
        )
    {
        $Self->{BaseDN}
            = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::BaseDN' . $Param{Count} );
    }
    else {
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => "Need Customer::AuthModule::LDAPBaseDN$Param{Count} in Kernel/Config.pm",
        );
        return;
    }
    if ( $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::UID' . $Param{Count} ) ) {
        $Self->{UID}
            = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::UID' . $Param{Count} );
    }
    else {
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => "Need 'Customer::AuthModule::LDAP::UID$Param{Count} in Kernel/Config.pm",
        );
        return;
    }
    $Self->{SearchUserDN}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::SearchUserDN' . $Param{Count} )
        || '';
    $Self->{SearchUserPw}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::SearchUserPw' . $Param{Count} )
        || '';
    $Self->{GroupDN}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::GroupDN' . $Param{Count} ) || '';
    $Self->{AccessAttr}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::AccessAttr' . $Param{Count} )
        || '';
    $Self->{UserAttr}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::UserAttr' . $Param{Count} )
        || 'DN';
    $Self->{UserSuffix}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::UserSuffix' . $Param{Count} )
        || '';
    $Self->{DestCharset}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Charset' . $Param{Count} )
        || 'utf-8';

    # ldap filter always used
    $Self->{AlwaysFilter}
        = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::AlwaysFilter' . $Param{Count} )
        || '';

    # Net::LDAP new params
    if ( $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Params' . $Param{Count} ) ) {
        $Self->{Params}
            = $Self->{ConfigObject}->Get( 'Customer::AuthModule::LDAP::Params' . $Param{Count} );
    }
    else {
        $Self->{Params} = {};
    }

    return $Self;
}

sub GetOption {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    if ( !$Param{What} ) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "Need What!" );
        return;
    }

    # module options

	###################################################################
	### Change by Igor Revyakin
	### change begin

    ###my %Option = ( PreAuth => 0, );
	my %Option = ( PreAuth => 1, );

	### change end
	###################################################################

    # return option
    return $Option{ $Param{What} };
}

sub Auth {
    my ( $Self, %Param ) = @_;

    # check needed stuff

	###################################################################
	### Change by Igor Revyakin
	### change begin

    ###for (qw(User Pw)) {
    ###    if ( !$Param{$_} ) {
    ###        $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
    ###        return;
    ###    }
    ###}
	my $User = $ENV{REMOTE_USER} || $ENV{HTTP_REMOTE_USER};
    # $Self->{LogObject}->Log(Priority => 'notice', Message => "User: $ENV{REMOTE_USER}");
    # $Param{User} = $Self->_ConvertTo( $Param{User}, $Self->{ConfigObject}->Get('DefaultCharset') );

    # Get username from email, recieved from libapache2-mod-auth-kerb // Changes by Andrey Tokarchuk
    my ($username, $domain) = $ENV{REMOTE_USER} =~ /(.*)@(.*)/;
    $Param{User} = $Self->_ConvertTo( $username, $Self->{ConfigObject}->Get('DefaultCharset') );

	### change end
	###################################################################
    $Param{Pw}   = $Self->_ConvertTo( $Param{Pw},   $Self->{ConfigObject}->Get('DefaultCharset') );

    # get params
    my $RemoteAddr = $ENV{REMOTE_ADDR} || 'Got no REMOTE_ADDR env!';

    # remove leading and trailing spaces
    $Param{User} =~ s/^\s+//;
    $Param{User} =~ s/\s+$//;

    # add user suffix
    if ( $Self->{UserSuffix} ) {
        $Param{User} .= $Self->{UserSuffix};

        # just in case for debug
        if ( $Self->{Debug} > 0 ) {
            $Self->{LogObject}->Log(
                Priority => 'notice',
                Message  => "CustomerUser: ($Param{User}) added $Self->{UserSuffix} to username!",
            );
        }
    }

    # just in case for debug!
    if ( $Self->{Debug} > 0 ) {
        $Self->{LogObject}->Log(
            Priority => 'notice',
            Message => "CustomerUser: '$Param{User}' tried to authentificate with Pw: '$Param{Pw}' "
                . "(REMOTE_ADDR: $RemoteAddr)",
        );
    }

    # ldap connect and bind (maybe with SearchUserDN and SearchUserPw)
    my $LDAP = Net::LDAP->new( $Self->{Host}, %{ $Self->{Params} } );
    if ( !$LDAP ) {
        if ( $Self->{Die} ) {
            die "Can't connect to $Self->{Host}: $@";
        }
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => "Can't connect to $Self->{Host}: $@",
        );
        return;
    }
    my $Result = '';
    if ( $Self->{SearchUserDN} && $Self->{SearchUserPw} ) {
        $Result = $LDAP->bind( dn => $Self->{SearchUserDN}, password => $Self->{SearchUserPw} );
    }
    else {
        $Result = $LDAP->bind();
    }
    if ( $Result->code ) {
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => 'First bind failed! ' . $Result->error(),
        );
        return;
    }

    # user quote
    my $UserQuote = $Param{User};
    $UserQuote =~ s/\\/\\\\/g;
    $UserQuote =~ s/\(/\\(/g;
    $UserQuote =~ s/\)/\\)/g;

    # build filter
    my $Filter = "($Self->{UID}=$UserQuote)";

    # prepare filter
    if ( $Self->{AlwaysFilter} ) {
        $Filter = "(&$Filter$Self->{AlwaysFilter})";
    }

    # perform user search
    $Result = $LDAP->search(
        base   => $Self->{BaseDN},
        filter => $Filter,
    );
    if ( $Result->code ) {
        $Self->{LogObject}->Log(
            Priority => 'error',
            Message  => 'Search failed! ' . $Result->error,
        );
        $LDAP->disconnect;
        return;
    }

    # get whole user dn
    my $UserDN = '';
    for my $Entry ( $Result->all_entries ) {
        $UserDN = $Entry->dn();
    }

    # log if there is no LDAP user entry
    if ( !$UserDN ) {

        # failed login note
        $Self->{LogObject}->Log(
            Priority => 'notice',
            Message  => "CustomerUser: $Param{User} authentication failed, no LDAP entry found!"
                . "BaseDN='$Self->{BaseDN}', Filter='$Filter', (REMOTE_ADDR: $RemoteAddr).",
        );

        # take down session
        $LDAP->unbind;
        $LDAP->disconnect;
        return;
    }

    # DN quote
    my $UserDNQuote = $UserDN;
    $UserDNQuote =~ s/\\/\\\\/g;
    $UserDNQuote =~ s/\(/\\(/g;
    $UserDNQuote =~ s/\)/\\)/g;

    # check if user need to be in a group!
    if ( $Self->{AccessAttr} && $Self->{GroupDN} ) {

        # just in case for debug
        if ( $Self->{Debug} > 0 ) {
            $Self->{LogObject}->Log(
                Priority => 'notice',
                Message  => 'check for groupdn!',
            );
        }

        # search if we're allowed to
        my $Filter2 = '';
        if ( $Self->{UserAttr} eq 'DN' ) {
            $Filter2 = "($Self->{AccessAttr}=$UserDNQuote)";
        }
        else {
            $Filter2 = "($Self->{AccessAttr}=$UserQuote)";
        }
        my $Result2 = $LDAP->search(
            base   => $Self->{GroupDN},
            filter => $Filter2
        );
        if ( $Result2->code ) {
            $Self->{LogObject}->Log(
                Priority => 'error',
                Message  => "Search failed! base='$Self->{GroupDN}', filter='$Filter2', "
                    . $Result->error,
            );
            $LDAP->unbind;
            $LDAP->disconnect;
            return;
        }

        # extract it
        my $GroupDN = '';
        for my $Entry ( $Result2->all_entries ) {
            $GroupDN = $Entry->dn();
        }

        # log if there is no LDAP entry
        if ( !$GroupDN ) {

            # failed login note
            $Self->{LogObject}->Log(
                Priority => 'notice',
                Message =>
                    "CustomerUser: $Param{User} authentication failed, no LDAP group entry found"
                    . "GroupDN='$Self->{GroupDN}', Filter='$Filter2'! (REMOTE_ADDR: $RemoteAddr).",
            );

            # take down session
            $LDAP->unbind;
            $LDAP->disconnect;
            return;
        }
    }

    # bind with user data -> real user auth.

	###################################################################
	### Change by Igor Revyakin
	### change begin

    ###$Result = $LDAP->bind( dn => $UserDN, password => $Param{Pw} );

	### change end
	###################################################################

    if ( $Result->code ) {

        # failed login note
        $Self->{LogObject}->Log(
            Priority => 'notice',
            Message  => "CustomerUser: $Param{User} ($UserDN) authentication failed: '"
                . $Result->error . "' (REMOTE_ADDR: $RemoteAddr).",
        );

        # take down session
        $LDAP->unbind;
        $LDAP->disconnect;
        return;
    }

    # login note
    $Self->{LogObject}->Log(
        Priority => 'notice',
        Message =>
            "CustomerUser: $Param{User} ($UserDN) authentication ok (REMOTE_ADDR: $RemoteAddr).",
    );

    # take down session
    $LDAP->unbind;
    $LDAP->disconnect;
    return $Param{User};
}

sub _ConvertTo {
    my ( $Self, $Text, $Charset ) = @_;

    return if !defined $Text;

    if ( !$Charset || !$Self->{DestCharset} ) {
        $Self->{EncodeObject}->Encode( \$Text );
        return $Text;
    }

    # convert from input charset ($Charset) to directory charset ($Self->{DestCharset})
    return $Self->{EncodeObject}->Convert(
        Text => $Text,
        From => $Charset,
        To   => $Self->{DestCharset},
    );
}

1;

Чтобы было понятнее, вот сам фикс:

    # $Param{User} = $Self->_ConvertTo( $Param{User}, $Self->{ConfigObject}->Get('DefaultCharset') );

    # Get username from email, recieved from libapache2-mod-auth-kerb // By Tok
    my ($username, $domain) = $ENV{REMOTE_USER} =~ /(.*)@(.*)/;
    $Param{User} = $Self->_ConvertTo( $username, $Self->{ConfigObject}->Get('DefaultCharset') );

Теперь авторизация для клиентов должна работать успешно.

Установка задания Cron

Делаем по официальному руководству. См. раздел «Настрой планировщика задач (cron jobs) для OTRS» на github.

Настройка кодировки отображения имён пользователей

У меня после установке и логине юзеров в тикетах их имена отображались неправильно (вместо них были иероглифы). Помогло следующее решение. В конфиге добавляем параметры:

$Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        Params => {
            ...
            SourceCharset => 'utf-8',
            DestCharset => 'utf-8',
            ..

Важные детали

1 Должна быть создана учётка helpdesk на AD
2. Открывать Otrs надо по символическому а не по IP адресу
3. На KDC должен быть сгенерирован keytab файл и скопирован на веб-сервер
4. wbinfo -u должен выдавать список юзеров, веб-сервер должен быть в домене

Тормозит OTRS

У меня возникла такая проблема. После прописывания сервера для исходящей почты OTRS стал дико тормозить (я про веб-интерфейс). Как оказалась проблема была в том, что он каждый раз при работе с почтой проверял действительность email адреса. Лечится это просто, я поставил эту настройку в «нет», и тормоза исчезли.

Администрирование -> Конфигурирование системы -> Framework:Core -> CheckMXRecord = Нет
Включает проверку MX record почтовых адресов клиента до отправки почты или приема почтовой или телефонной заявки.

Ссылки

OTRS Appliance (iso)
OTRS Installation manual
Установка OTRS на Ubuntu Server
Настройка OTRS
Интеграция с Active Directory
OTRS:ITSM
Ставим OTRS на Ubuntu по-быстрому
Установка OTRS и интеграция с Active Directory
Kerberos в Active Directory
Кодировка имён пользователей

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


22 Responses to “OTRS: Установка на Ubuntu, аутентификация в Active Directory и Single sign on”

  1. Геннадий:

    Здравствуйте.
    Вроде делаю все так же как у Вас написано, но не получается получить имя пользователя через whoami.pl (в phpinfo так же не нашел где его можно смотреть). Может есть какие-то еще тонкости, которые у Вас не указаны?
    А так же вопрос — при генерации кейтаба «-mapuser helpdesk@DOMAIN.RU» отвечает за сопоставление пользователя созданного в АД? а то про него в статье так же ничего не нашел.
    Буду рад любым подсказкам.

  2. Сергей:

    Здравствуйте! Спасибо за статью!
    Возникла одна проблема, а т.к. я делаю все исключительно по ней — у вас эта проблема наверняка тоже была: на моменте запуска установочного скрипта (otrs/installer.pl) вместо страницы настройки firefox, как и другие браузеры, предлагает скачать installer.pl

  3. zor6kin:

    Здравствуйте, огромное спасибо за статью!
    Возникло 2 вопроса:
    Centos 6.5 +otrs 4.0.6
    1. после добавлении .htaccess в каталог /opt/otrs/bin/cgi-bin/
    страничка custmasers.pl и index.pl не грузятся
    2. whoami.pl в архиве нет, создал файл через vi /opt/otrs/bin/cgi-bin/whoami.pl — я так понимаю к ней путь нужно прописать в httpd.conf ?

    • google.com Андрей Токарчук:

      Александр, спасибо за отзыв)
      Итак, по вопросам.
      1. Не грузится, а что в логах веб-сервера? Сообщения должны раскрывать суть проблемы, может пуь не тот или прав не хватает.
      2. Вот ссылка на whoami.pl http://pastebin.com/3FnurQQ8 Он должен быть в корне веб-сервера (ну т.е. в public_html папке или как она у вас называется). Для начала протестируйте открытие простого текстового файла, если всё ок, то перлового скрипта, дальше whoami, дальше уже файлов otrs. Отлаживайте по шагам.

  4. aceko:

    Выполнил все как у вас в инструкции но при входе на Customer.pl выдает в логах апача ошибку в файлы adsso 39 строка на функцию no logobject
    В чом может быть проблема?
    Стоит ubuntu 14

    • google.com Андрей Токарчук:

      Сергей, а whoami говорит?

      • Aceko:

        You appear to be user , logged into the Windows NT domain .

      • Валерий:

        Та же проблема.
        Апач 2.4.10, модуль никак не могу найти для авторизации.

        • google.com Андрей Токарчук:

          Валерий, мы в общем уже на SpiceWorks перешли :-)

          • Валерий:

            Какие прелести и отличия?
            Думаю перейти на что-то новое или на 4й OTRS. Мониторинг не нужен. Есть Zabbix

          • google.com Андрей Токарчук:

            SpiceWorks работает на Windows, со всеми вытекающими плюсами и минусами :) В более ранних версиях подтекала периодически, сейчас вроде нормально работает.

  5. Станислав:

    Добрый день. Коллеги помогите пожалуйста в таком вопросе. Установлена otrs appliance на Debian, не могу сбросить пароль на системного рута, что бы зайти с консоли и изменить настройки системы. При запуске синий экран нажмите F2 для обслуживания.

  6. Станислав:

    Андрей мне детальная инструкция не нужна, скажите хоть в какую сторону копать

  7. Андрей:

    добрый день, установил OTRS все отлично работает, но в логах много таких записей
    OTRS-otrs.Scheduler-56[14423]: [Debug][main::_Status][580] Scheduler Daemon status request! PID 5960
    OTRS-otrs.Scheduler-56[14692]: [Debug][main::_Status][580] Scheduler Daemon status request! PID 5960

    подскажите, как мне отключить этот Debug?

    • google.com Андрей Токарчук:

      Андрей, доброго дня! Насколько я помню, там где-то в gui была ссылка, которая включает скрипты по планировщику. Думаю после включения таких ошибок не будет. Пробуйте.

      • Андрей:

        спасибо за быстрый ответ
        а без доступа в gui можно как-то исправить?
        сейчас в кроне такие задания
        20 0 * * 0 $HOME/bin/otrs.DeleteCache.pl —expired >> /dev/null
        30 0 * * 0 $HOME/bin/otrs.LoaderCache.pl -o delete >> /dev/null
        5 * * * * $HOME/bin/otrs.GenerateDashboardStats.pl >> /dev/null
        */20 * * * * $HOME/bin/otrs.GenericAgent.pl >> /dev/null
        */10 * * * * $HOME/bin/otrs.GenericAgent.pl -c db >> /dev/null
        45 */2 * * * $HOME/bin/otrs.PendingJobs.pl >> /dev/null
        10 0 * * * $HOME/bin/otrs.ReprocessMails.pl >> /dev/null
        */10 * * * * $HOME/bin/otrs.PostMasterMailbox.pl >> /dev/null
        01 01 * * * $HOME/bin/otrs.RebuildTicketIndex.pl >> /dev/null
        */5 * * * * $HOME/bin/otrs.Scheduler.pl -w 1 >> /dev/null
        55 */2 * * * $HOME/bin/otrs.DeleteSessionIDs.pl —expired >> /dev/null
        35 * * * * $HOME/bin/otrs.UnlockTickets.pl —timeout >> /dev/null

        и вот эти закомментированы
        */5 * * * * [ -x /usr/bin/fetchmail ] && /usr/bin/fetchmail -a >> /dev/null
        */5 * * * * /usr/bin/fetchmail -a —ssl >> /dev/null
        0 23 * * * $HOME/bin/otrs.GenericAgent.pl -c «Kernel::Config::GenericAgentMove» >> /dev/null

        • google.com Андрей Токарчук:

          К сожалению в данный момент он у меня не установлен и уже не помню, что там и как.

          • Андрей:

            я так понимаю в логе такие записи вызывает крон
            */5 * * * * $HOME/bin/otrs.Scheduler.pl -w 1 >> /dev/null
            т.к. у меня каждые 5 минут такая запись в логе есть

            что означает ключ «-w 1»? и вообще нужен ли вообще такой крон?

Комментировать