Аутентификация пользователей в Ubuntu с помощью PostgreSQL

Приветствую всё хабрасообщество!
Встала у меня как-то раз задача организовать авторизацию пользователей в Ubuntu по PostgreSQL-базе.
На просторах Интернета много информации по настройке авторизации через MySQL, а вот по PostgreSQL — информации крайне мало, и поэтому, кое-что пришлось адаптировать.
Не секрет, что Linux можно заставить авторизоваться через что угодно, хоть через фейсбук или вконтакт, и служат для этого модули авторизации PAM и NSS.
Рассмотрим на примере Ubuntu 10.04 как настроить такую авторизацию.


Итак — приступим.

1. Ставим PAM и NSS модули авторизации:
sudo apt-get install libpam-pgsql libnss-pgsql

2. Создаём таблицы в PostgreSQL, которые будут содержать наших пользователей и группы. Таблицы повторяют структуры системных файлов groups, passwd и shadow.

-- Группы
CREATE TABLE sysauth_groups
(
"name" character varying(128), -- Название группы
pass character varying(128), -- Пароль
gid integer, -- id группы
members character varying(512) -- члены группы
);

-- Пользователи
CREATE TABLE sysauth_passwd
(
"name" character varying(128), -- имя пользователя
pass character varying(128), -- Пароль (если используется система теневых паролей - должен содержать 'x'
gecos character varying(512), -- Информация о пользователе
home character varying(256), -- Домашняя директория
shell character varying(256), -- Оболочка
uid integer, -- ID пользователя
gid integer -- ID группы
)

-- Теневые пароли
CREATE TABLE sysauth_shadow
(
uid integer, -- id пользователя (в соответствии с таблицей passwd)
"name" character varying(128), -- имя пользователя
"password" character varying(128), -- пароль пользователя
last_changed integer, -- Дата последней смены пароля
min integer,
max integer,
warn integer,
inact integer,
expire integer, -- Срок истекания пароля
flag character varying(8)
);

3. Создадим тестового пользователя и группу. Пароль для тестового пользователя - 12345. Если не подойдёт - сгенерируйте его стандартным crypt'ом

insert into sysauth_groups(name, pass, gid, members) values ('test_group', 'x', 5000, '');
insert into sysauth_passwd(name, pass, gecos, home, shell, uid, gid) values ('test_user', 'x', ',,,,', '/home/test_user', '/bin/bash', 5000, 5000);
insert into sysauth_shadow(uid, name, password, last_changed, min, max, warn, inact, expire, flag) values (5000, 'test_user', '$6$P5jfk4Ufh33f$.Dc8H9jsWAl/igt4QPbYI/El28SyUEAoJPPHsLIGMKOymhC7AIaiizlW5W9hm7kU7PYMCySEhYtMqVPFsVTMK/', 14735, 0, 99999, 7, 0, 999999, '');


Теперь перейдем к настройке модулей авторизации.

4. Настраиваем NSS:

Файл/etc/nsswitch.conf:

# /etc/nsswitch.conf

#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd: compat pgsql
group: compat pgsql
shadow: compat pgsql

hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4
networks: files

protocols: db files
services: db files
ethers: db files
rpc: db files

netgroup: nis


Файл /etc/nss-pgsql.conf (должен иметь права на чтение для всех)

# Строка соединения с БД. Подставьте свои параметры
connectionstring = hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres connect_timeout=15

# you can use anything postgres accepts as table expression

# Must return "usernames", 1 column, list
getgroupmembersbygid = SELECT name FROM sysauth_passwd ORDER BY name

# Must return passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid
getpwnam = SELECT name, pass, gecos, home, shell, uid, gid FROM sysauth_passwd WHERE name=$1

# Must return passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid
getpwuid = SELECT name, pass, gecos, home, shell, uid, gid FROM sysauth_passwd WHERE uid=$1

# All users
allusers = SELECT * FROM sysauth_passwd

# Must return group_name, group_passwd, group_gid
getgrnam = SELECT name, pass, gid, members FROM sysauth_groups WHERE name=$1

# Must return group_name, group_passwd, group_gid
getgrgid = SELECT name, pass, gid, members FROM sysauth_groups WHERE gid=$1

# Must return gid. %s MUST appear first for username match in where clause
# Другие группы пользователя
groups_dyn = select null
allgroups = select name, pass, gid, members from sysauth_groups

#groups_dyn = SELECT ug.gid FROM passwd_table JOIN usergroups USING (uid) where username = $1 and ug.gid <> $2
#allgroups = SELECT groupname, passwd, gid, ARRAY(SELECT username FROM usergroups WHERE usergroups.gid = group_table.gid) AS members FROM group_table


Файл /etc/nss-pgsql-root.conf (должен иметь права на чтение только для рута, используется для авторизации по теневым паролям)

connectionstring = hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres connect_timeout=15

shadowbyname = SELECT name, password, last_changed, min, max, warn, inact, expire, flag FROM sysauth_shadow WHERE name = $1
shadow = SELECT name, password, last_changed, min, max, warn, inact, expire, flag FROM sysauth_shadow


Теперь — проверим, как оно работает, и работает ли вообще:

sudo getent group
sudo getent passwd
sudo getent shadow

Эти команды должны помимо стандартных юзеров и групп выдать нашего тестового пользователя из БД.

5. Настраиваем PAM (авторизация gdm и т.д.). Настройки PAM могут отличаться в разных системах

Файл /etc/pam_pgsql.conf

connect = hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres connect_timeout=15

debug = 1

auth_query = select pass from sysauth_passwd where name = %u
acct_query = select false, false, false, false from sysauth_passwd where name = %u

# Это используется для смены пароля
pwd_query = update sysauth_shadow set password = %p where name = %u



Файл /etc/pam.d/common_auth

ищем
auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass


делаем

auth [success=3 default=ignore] pam_unix.so nullok_secure
auth [success=2 default=ignore] pam_pgsql.so try_first_pass
auth [success=1 default=ignore] pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass


Файл /etc/pam.d/common_account
ищем

account [success=2 new_authtok_reqd=done default=ignore] pam_unix.so
account [success=1 new_authtok_reqd=done default=ignore] pam_winbind.so


делаем

account [success=3 new_authtok_reqd=done default=ignore] pam_unix.so
account [success=2 new_authtok_reqd=done default=ignore] pam_pgsql.so
account [success=1 new_authtok_reqd=done default=ignore] pam_winbind.so


Чтоб хомяк юзера создавался автоматом — в файле
/etc/pam.d/common_session
добавляем куда-нибудь почти в конец
session required pam_mkhomedir.so umask=0022 skel=/etc/skel/ silent
Вроде всё, должно работать. Проверяем:

su test_user
Если смена пользователя прошла успешно — всё отлично, перезапускаем gdm, пытаемся залогиниться юзером из базы. Должно всё получиться.

Успехов!
Теги:
linux, ubuntu, аутентификация, pam, nss, postgresql

Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.