24 июня 2009 г.

Ldap авторизация в Django

Вопрос ldap авторизации в Python довольно хорошо рассмотрен. Теперь разберем, как привязать эту авторизацию к Django.
Первый вариант в рамках компании будет регистрация на сайте с django путем авторизации в ldap.
Другой вариант - полная интеграция авторизации ldap в джанго, но тогда все преимущества групп и контроля доступа теряются, если только не получать эту дополнительную информацию от ldap или других источников.
Третий, наиболее гибкий вариант. Отсутствие регистрации. Логиним пользователя - ищем его профиль в auth у Django - если его нет, создаем, если есть - то используем найденный профиль (если пароль в Django не совпадает с ldap паролем - обновляем его).

Давайте пойдем по третьему пути.

Для начала подготавливаем Django. У нас будет расширенный стандартный Django User, так как после авторизации пользователя в ldap мы еще получим его данные с корпоративной базы mssql.

Устанавливаем python-ldap:
  1. $ sudo apt-get install python-ldap  

Прописываем в settings.py:
  1. LDAP_DOMAIN='mydomain.com'    
  2. LDAP_SERVER='ldaps://%s' % LDAP_DOMAIN #SSL connection  

Правим файл auth.py:
  1. # -*- coding: utf-8 -*-  
  2.   
  3. from django.conf import settings  
  4. from django.contrib.auth.backends import ModelBackend  
  5. from django.core.exceptions import ImproperlyConfigured  
  6. from django.db.models import get_model  
  7. from social.models import CustomUser   
  8.   
  9. class CustomUserModelBackend(ModelBackend):  
  10.       
  11.     def get_local_user(self, email, password=None):  
  12.               
  13.         try:  
  14.             user = self.user_class.objects.get(email=email.lower())  
  15.             if user.check_password(password):  
  16.                 return user  
  17.             else:  
  18.                 self.exist_user=user#save user for refresh local data  
  19.         except self.user_class.DoesNotExist:  
  20.             return None  
  21.   
  22.     def get_ldap_refresh_create_user(self, username=None, password=None):  
  23.         import ldap, sys  
  24.           
  25.         #create new local user  
  26.         if '@' in username:  
  27.             #user@domain  
  28.             LDAP_USERNAME=username  
  29.             username=username.split('@')[0]  
  30.         else:  
  31.             #user  
  32.             LDAP_USERNAME='%s@%s' % (username, settings.LDAP_DOMAIN)  
  33.           
  34.         LDAP_PASSWORD=password  
  35.   
  36.         try:    
  37.              # build a client    
  38.              ldap_client = ldap.initialize(settings.LDAP_SERVER)    
  39.              # perform a synchronous bind    
  40.              ldap_client.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD)  
  41.         except ldap.INVALID_CREDENTIALS, e:    
  42.              return False  
  43.         except ldap.SERVER_DOWN, e:    
  44.              return False#@todo raise Validation error  
  45.           
  46.         #lpad auth succes:  
  47.           
  48.         #try to get local user  
  49.         user=self.get_local_user(LDAP_USERNAME, password)  
  50.           
  51.         if user:#if we check user in localbase  
  52.             return user  
  53.         else:#else create new or refresh old pass   
  54.             if hasattr(self'exist_user'):  
  55.                 #refresh local auth data from ldap in case of change pass  
  56.                 self.exist_user.set_password(password)  
  57.                 self.exist_user.save()#write new pass  
  58.                 user=self.exist_user  
  59.             else:  
  60.                 user=CustomUser.objects.create_user(username,LDAP_USERNAME,password)  
  61.                   
  62.             return user  
  63.       
  64.     def updape_user_info(self, user):  
  65.         pass  
  66.            
  67.     def authenticate(self, username=None, password=None):  
  68.         #try to auth with ldap  
  69.         #and refresh user data in success or create new one if user does not exist  
  70.         user=self.get_ldap_refresh_create_user(username, password)  
  71.         if user:  
  72.             self.updape_user_info(user)#get data from mssql  
  73.             return user  
  74.         else:  
  75.           return None# error ldap auth  
  76.           
  77.     def get_user(self, user_id):  
  78.         try:  
  79.             return self.user_class.objects.get(pk=user_id)  
  80.         except self.user_class.DoesNotExist:  
  81.             return None  
  82.  
  83.     @property  
  84.     def user_class(self):  
  85.         if not hasattr(self'_user_class'):  
  86.             #self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 3))  
  87.             self._user_class = CustomUser  
  88.             if not self._user_class:  
  89.                 raise ImproperlyConfigured('Could not get custom user model')  
  90.         return self._user_class  


Функция updape_user_info на самостоятельное написание, она должна дописывать необходимую расширенную информацию.

ps. прозрачная авторизация в принципе возможна, но только с IE, можете попробовать.

blender - быстрый старт

Если вам уж очень хочется нарисовать что-то в 3D, сделать рендер или анимацию и бесплатно, то вам - прямая дорога к blender. Но при первом знакомстве Вы обнаружите, что интерфейс программы не дружественен к пользователю.

Здесь хотел было рассказать о базовых функциях, но позже нашёл все то, о чем я хотел рассказать:

Blender QuickStart или Blender шпаргалка


Добавлю, что выделение всех элементов меша в режиме редактирования - кнопочка - A.

Со временем, думаю буду добавлять полезные кнопки управления, ибо если не работать с blenderом профессионально или хотя бы регулярно, то все это очень быстро забывается.

А шпаргалка действительно отличнейшая, спасибо автору.

3 июня 2009 г.

Установка Redmine на FreeBSD 7.2, используя apache, mod_rails и postgres sql

Разобравшись с git сервером и GUI клиентами в прошлой статье, я обещал рассмотреть установку GitPlugin для Trac (пользуюсь давно, все устраивало, когда был SVN). Но сейчас меня смутили несколько вещей:
1. Trac не поддерживает git из коробки (реализован в виде плагина, что не есть уже хорошо).
2. Trac хорош для одного крупного проекта (для запуска дополнительного надо много телодвижений), а мы хотим построить СКВ для многих проектов.
3. В trac нет русификации, а она желательна (возможен доступ пользователей программ для создания задач или сообщений о багах).
4. В trac нет удобной системы распределения прав (есть конечно дополнительные пакеты, но если все это сложить, получается уж очень громоздко).

Поэтому я решил поискать систему, которая бы меня устраивала.
И я ее нашел, redmine. Он написан на Ruby, поддерживает кучу баз данных, есть русский язык, лишен всех недостатков перечисленных выше, самое главное, поддерживает git "из коробки"!

Краткий обзор возможностей отсюда:

* Поддержка нескольких проектов в одной базе данных;
* Гибкая система настройки пользовательских прав доступа;
* Гибкая система тикетов и заданий;
* Поддержка календаря и графиков Гантта
* Поддержка файлового архива, документация и новостных лент по проекту
* Сквозное логирование событий в системе и поддержка отсылки на еmail
* Встроенная система Wiki по проекту
* Встроенная система форумов по проекту
* Простая система учета времени
* Возможность добавлять произвольные пользовательские поля к проектам, заданиям и пользователям
* Интеграция с системами контроля версий (SVN, CVS, Mercurial, Bazaar and Darcs)
* Поддержка LDAP авторизации
* Поддержка регистрации пользователей
* Мультиязычность (Русский и Украинский присутствуют)
* Поддержка различных баз данных


Дополню, что git тоже поддерживается.

Начнем.

Системе 3 года, но уже информации по ней много, все хвалят, соответственно в поиске можно найти много мануалов по установке прямо под вашу систему.
Но мы пройдем этот путь заново :)
Считаем, что apache2 и postgres 8.3 уже установлен.

Следуем официальному руководству по установке:

1. Проверяем и устанавливаем необходимые пакеты:
  1. #ruby --version  
  2. ruby 1.8.7 (2007-03-13 patchlevel 0) [i386-freebsd7]  
  3. #cd /usr/ports/www/rubygem-rails  
  4. #make clean install  

Этот пакет содержит все компоненты, которые необходимы для запуска Ruby On Rails (собственно, на котором и написан redmine).
Таблицу с необходимыми версиями смотрим здесь.

У меня с портами REALEASE-7.2 встала версия 2.3.2
  1. #cd /usr/ports/converters/ruby-iconv  
  2. #make clean install  

2. Скачиваем стабильную ветку:
  1. #wget http://rubyforge.org/frs/download.php/56909/redmine-0.8.4.tar.gz  
  2. #tar -zxvf redmine-0.8.4.tar.gz  

3. Конфигурируем базу данных.
Добавляем пользователя redmine в базу данных postgres:
  1. #su pgsql  
  2. $createuser redmine -–no-superuser -–no-createdb -–no-createrole -–login –-pwprompt -–encrypted  
  3. $createdb --owner=redmine --encoding=utf-8 redmine  
  4. $exit  

Редактируем pg_hba.conf при необходимости.

Копируем ~/redmine-0.8.4/config/database.yml.example в ~/redmine-0.8.4/config/database.yml и редактируем:
  1. production:  
  2.   adapter: postgresql  
  3.   database: redmine  
  4.   host: localhost  
  5.   username: redmine  
  6.   password: password  
  7.   encoding: utf8  

Заполняем базу данных схемой Redmine, выполнив команду в директории redmine-0.8.4:
  1. #rake db:migrate RAILS_ENV="production"  

Загружаем первоначальную конфигурацию Redmine:
  1. #rake redmine:load_default_data RAILS_ENV="production"  

4. Устанавливаем права.
Пользователь www должен иметь право писать в директории files, log, tmp.
  1. #cd redmine-0.8.4  
  2. #chown -R www:www files log tmp public/plugin_assets  
  3. #chmod -R 755 files log tmp public/plugin_assets  

5. Пробный запуск.
  1. #sudo -u www ruby script/server webrick -e production  

Переходим по адресу http://SERVER:3000/, все должно работать.
Можно залогиниться от admin, пароль admin.

Примеры настройки smtp сервера здесь.

6. Связываем apache и Redmine.
Есть официальное how to.

Мне оно не понравилось, использует CGI, в общем все кисло :)
Гораздо более интересно решение "Настройка Redmine на работу через apache and mongrel_cluster по HTTPS", изначально подсмотренное здесь.
Предлагается использовать mongrel в качестве бэкенда к серверу apache.
Mongrel является HTTP-сервером и библиотекой на Ruby, которая предназначена для хостинга разнообразных веб-приложений написанных на языке программирования Ruby, используя HTTP протокол, а не FastCGI или SCGI.
Вот это уже гораздо интересней. Тем более https.

Но я решил пойти немного другим путем, установкой Phusion Passenger (aka mod_rails).
  1. # cd /usr/ports/www/rubygem-passenger  
  2. # make clean install  

Настраиваем апач:

Доступные настройки mod_rails:
* RailsEnv - задает среду выполнения приложения. Значение по умолчанию: production.
* RailsBaseURI - задает директорию, в которую размещается приложение. По этому адресу должна находиться директория public приложения.
* RailsRuby - задает интерпретатор, который будет использован для выполнения приложения. Имеет смысл, если у Вас установлено несколько интерпретаторов Руби.
* RailsMaxPoolSize - максимальное количество запущенных экземпляров приложения. Оптимально значение зависит от конфигурации системы. Значение по умолчанию: 20.
* RailsPoolIdleTime - максимальное время бездействия экземпляра приложения в секундах. По истечении этого времени экземпляр приложения будет остановлен для экономии памяти. Разработчики рекомендуют в качестве оптимального значения 2*x, где x - время, которое пользователь тратит на просмотр страницы. Значение по умолчанию: 120.

Настроен апач примерно так.
Создаем сертификаты.

А потом настраиваем секьюрный хост:
  1. SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM  
  2. SSLMutex file:/usr/local/etc/apache22/logs/ssl_mutex  
  3. SSLSessionCache shm:/usr/local/etc/apache22/logs/ssl_cache_shm  
  4. SSLSessionCacheTimeout 600  
  5.   
  6. <ifmodule mime.c="">  
  7.     AddType application/x-x509-ca-cert      .crt  
  8.     AddType application/x-pkcs7-crl         .crl  
  9. </ifmodule>  
  10.   
  11. SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0  
  12.   
  13. NameVirtualHost *:80  
  14.   
  15. LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.2/ext/apache2/mod_passenger.so  
  16. PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.2  
  17. PassengerRuby /usr/local/bin/ruby18  
  18.   
  19. PassengerDefaultUser www  
  20. PassengerMaxPoolSize 1  
  21. PassengerUseGlobalQueue on  
  22. PassengerMaxInstancesPerApp 1  
  23.   
  24. <virtualhost *:80="">  
  25.     ServerName SERVER  
  26.       
  27.     ErrorLog etc/apache22/logs/httpd-redmine.log  
  28.   
  29.     RewriteEngine On  
  30.     Options +FollowSymlinks  
  31.     RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=permanent]  
  32. </virtualhost>  
  33.         
  34. <virtualhost *:443="">  
  35. RailsEnv production  
  36. ServerName SERVER  
  37.   
  38. SSLEngine on  
  39. SSLVerifyClient none  
  40. SSLCertificateFile etc/apache22/keys/new.crt  
  41. SSLCertificateKeyFile etc/apache22/keys/new.key  
  42. SSLCACertificateFile etc/apache22/keys/cacert.pem  
  43. SSLProtocol all -SSLv2  
  44. DocumentRoot /tank/redmine/redmine-0.8.4/public  
  45. ErrorLog etc/apache22/logs/httpsd-redmine.log  
  46.   
  47. <directory tank="" redmine="" redmine-0.8.4="" public="">  
  48.     Options FollowSymLinks  
  49.     AllowOverride None  
  50.     SSLOptions +StdEnvVars  
  51.     Order allow,deny  
  52.     Allow from all  
  53. </directory>  
  54. </virtualhost>  

Проверяем конфигурацию apache:
  1. #/usr/local/etc/rc.d/apache22 configtest  

Стартуем и может быть получаем ошибку
  1. Error message:  
  2.     No such file or directory - /nonexistent  
  3. Exception class:  
  4.     Errno::ENOENT  

если у нашего пользователя www нет домашней директории. Решается это так:

Покопавшись немного обнаружил, что проблема вызвана конфликтом Passenger и gem и исправляется внесением изменений в файл rubygems.rb в метод self.set_paths.
Необходимо заменить код

# only create by matching user
next if Etc.getpwuid.uid != File::Stat.new(Gem.user_home).uid

на:

# only create by matching user
home_folder_uid = File::Stat.new(Gem.user_home).uid rescue nil
next if Etc.getpwuid.uid != home_folder_uid

Файл находится здесь /usr/local/lib/ruby/site_ruby/1.8/rubygems.rb .

Перезапускаем апач, http://SERVER (должен выполниться редирект на https://SERVER).

Настройка самого redmine через веб-интерфейс интуитивно понятна, удачи!



PS. Кстати, напоследок линк: Git User's Manual

1 июня 2009 г.

Установка git сервера на Freebsd 7.2 c клиентами EGit на Eclipse под Windows

Введение в git.

Система спроектирована как набор программ, специально разработанных с учётом их использования в скриптах. Это позволяет удобно создавать специализированные системы контроля версий на базе Git или пользовательские интерфейсы. Например, Cogito является именно таким примером фронтенда к репозиториям Git. А StGit использует Git для управления коллекцией патчей.

Git поддерживает быстрое разделение и слияние версий, включает инструменты для визуализации и навигации по нелинейной истории разработки. Как и Darcs, BitKeeper, Mercurial, SVK, Bazaar и Monotone, Git предоставляет каждому разработчику локальную копию всей истории разработки, изменения копируются из одного репозитория в другой.

Удалённый доступ к репозиториям Git обеспечивается git-daemon, SSH, или HTTP сервером. TCP-сервис git-daemon входит в дистрибутив Git и является наряду с SSH наиболее распространённым и надёжным методом доступа. HTTP метод доступа, несмотря на ряд ограничений, очень популярен в контролируемых сетях, потому что позволяет использование существующих конфигураций сетевых фильтров.


Установка.
  1. cd /usr/ports/devel/git  
  2. make && make install  

Для публичного доступа к репозиторию можно воспользоваться git-daemon.
Также возможен доступ через http (апач+dav+gitweb).
Я же выбрал более простой и надёжный путь - ssh.

Для начала определимся с сервером.
Создаем пользователя, который будет работать с репозиториями, а так же являться администратором gitosis: gituser (создаем без пароля).
  1. $sudo adduser gituser  

При создании, в качестве домашней указываем корневую директорию с репозиториями.

Для начала мы сосредоточимся на авторизации пользователя через ssh.
Для этого, проверим настройки sshd, примерно как здесь.

Устанавливаем gitosis, набор скриптов, которые выполняются при открытии ssh-сессии, позволяют использовать ssh ключи для авторизации в репозиториях, а также освобождают от необходимости создавать много пользователей в системе для доступа к репозиториям.
  1. $git clone git://eagain.net/gitosis.git  
  2. $cd gitosis  
  3. $sudo python setup.py install  

Далее надо создать gitosis-хостинг с авторизацией только по ключам:
То есть проинициализировать репозиторий самого gitosis в указанной нами директории.
Я решил управление gitosis оставить на сервере.
  1. $ssh-keygen -t rsa  

Эта команда создает в домашней директории пользователя gituser пару id_rsa и id_rsa.pub. Первый файл - секретный, должен быть закрыт от любого пользователя на системе, а так же не передаваться по сети.
Второй ключ публичный, мы его должны передать в gitosis при инициализации gitosis. Его рекомендуют скопировать в директорию, доступную всем для чтения, например /tmp . Далее инициализируем gitosis и его репозиторий.
(Первые две команды, в случае, если у вас не установлен sudo.)
  1. #cd /usr/ports/security/sudo ; make install clean  
  2. #rehash  
  3. #sudo -H -u gituser gitosis-init < /tmp/id_rsa.pub  
  4. Initialized empty Git repository in /tank/gitrepos/repositories/gitosis-admin.git/  
  5. Reinitialized existing Git repository in /tank/gitrepos/repositories/gitosis-admin.git/  

ключ -H обязателен, иначе команда sudo будет выполняться в домашнюю директорию предыдущего пользователя (например /root).

Теперь у нас есть несколько директорий в домашней директории gituser. Папка repositories предназначена для хранения репозиториев, там уже находится репозиторий настроек gitosis (gitosis-admin).

Если у вас старый setuptools, рекомендуют прописать следующие права:
  1. sudo chmod 755 ~/repositories/gitosis-admin.git/hooks/post-update  

Далее, заходим под пользователем gituser и забираем репозиторий администрирования gitosis:
  1. $git clone gituser@YOUR_SERVER_HOSTNAME:gitosis-admin.git  
  2. $cd gitosis-admin  

Это удаленно, а у так как у нас админ на этом же хосте, то локально:
  1. #su gituser  
  2. $cd ~/tmp  
  3. $git clone ~/repositories/gitosis-admin.git gitosis-admin  
  4. $cd gitosis-admin  

Создание "репозиториев" в gitosis.
Редактируем файл gitosis.conf:
  1. [group projectteam]  
  2. members = vasya  
  3. writable = project  

где project - название будущего репозитория.

Создаем публичный ключ в клиенте windows.
Для этого используем пакет msysGit. Я выбрал portable версию, ибо нам из пакета нужен только генератор ssh ключей (PortableGit\bin\ssh-keygen.exe).
  1. >ssh-keygen -C “vasya” -t rsa  

Обычно пара сохраняется в папку c:\\Documents and Settings\\Username\\.ssh на XP или c:\\Users\\Username\\.ssh на Vista. Заливаем публичный ключ (vasya.pub) в директорию gitosis-admin/keydir, место куда мы извлекли репозиторий настроек gitosis.

"Пушим" настройки в репозиторий gitosis.
  1. git add keydir/vasya.pub  
  2. git commit -a -m "Allow vasya write access to project"  
  3. git push  

После этого проверить, что файл конфигурации изменился (есть ссылка в домашней директории gituser), а также скопировались ключи в ~/repositories/gitosis-admin.git/gitosis-export/keydir. При загрузке в репозиторий gitosis сам извлекает изменившееся файлы в директорию gitosis-admin.

Создаем репозиторий на сервере под юзером gituser:
  1. $mkdir ~/repositories/project.git  
  2. $cd project.git  
  3. $git --bare init  

--bare обозначает, что у нас нет намерения хранить файлы самого проекта на сервере, только diff и файлы, которые генерирует сам git (проще говоря, структура git репозитория). Что кстати, совершенно достаточно даже для Git Plugin for Trac, который мы намереваемся установить.

Теперь нам необходимо создать ветку (branch), иначе EGit будет ругаться на отсутствие оных. Выполнить push на полностью пустом репозитории нельзя.
Для первого коммита автоматически создается бранч с именем master, в него же по умолчанию попадают следующие коммиты
  1. #su gituser  
  2. $cd ~/tmp  
  3. $git clone ~/repositories/project.git project  
  4. $cd project  
  5. $echo "test" > test  
  6. $git add test  
  7. $git commit -a -m "initial branch"  
  8. $git push origin master  

Попробуем получить проект через ssh с помощью плагина EGit.
Установка eclipse и самого плагина очень проста.
В меню eclipse выбираем File-Import, Git Repository. Выбираем протокол git+ssh:// , указываем путь:

git+ssh://gituser@SERVER/project.git

Самое главное! eclipse прописывает путь к ssh, как $HOME/ssh. Его необходимо поправить на $HOME/.ssh в меню:
Window-Preferences - General - Network Connection - SSH2. Там же можно управлять ключами и просматривать их. Если eclipse не найдет ключи ничего забираться не будет.
Дальнейшие действия по добавлению проекта интуитивно понятны.

Единственное, в новой версии появилась галочка Import projects after clone, которую надо снять, ибо она у меня привела к пустому списку проектов, попробуйте, может у вас получится. Это не страшно, по вышеприведенному примеру указано как просто сделать share project с извлеченного проекта на диске (плюс показано ниже).

Можно также забрать проект через консоль:

Запускаем PortableGit\git-cmd.bat и выполняем:
  1. >git clone gituser@SERVER:project.git  

Далее, создаем проект в eclipse, добавляем в него наш извлеченный проект (Import-File System), жмем на проекте Team-Share (Git) и все, наш проект теперь помечен, как гит репозиторий. Пробуем менять файлы, коммитить и пушить.



Если возникают какие-либо проблемы, то смотрим /var/log/auth.log .
А также в eclipse ( Help - About Eclipse - Configuration Details - View Error Log).
Также можно добавить после строчки [gitosis] в gitosis.conf:
  1. loglevel=DEBUG  

При задании которого при обращении к gitosis (через консольный клиент) будут выведена дополнительная информация при ошибках.

Об установке багтрекера Trac для git, а также использовании git в Visual Studio в следующий раз.