barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

вторник, 10 января 2012 г.

Небольшое HOWTO по прикручиванию авторизации и аутентификации с помощью Spring Security к уже существующему веб-приложению

Итак, изначально ситуация была следующая: есть небольшое веб-приложение на JSP, не использующее никаких фреймворков. Задача - добавить в него авторизацию и аутентификацию с помощью фреймворка Spring Security.
Поискав в инете я так и не нашел какого-нибудь работающего примера как сделать так, чтобы "оно заработало", а потом уже разбираться в тонкостях и возможностях Spring Security. Примеры были либо непонятные, либо по Spring Security 2.х, тогда как мне хотелось работать сразу с 3.х (точнее, 3.1).
После некоторых проб и ошибок получилось найти следующий алгоритм:
1) Подключаем к проекту библиотеки спринга:
  • org.springframework.core-3.1.0.RELEASE.jar
  • org.springframework.beans-3.1.0.RELEASE.jar
  • org.springframework.context-3.1.0.RELEASE.jar
  • org.springframework.expression-3.1.0.RELEASE.jar
  • org.springframework.web-3.1.0.RELEASE.jar
2) Подключаем библиотеки Spring Security:
  • spring-security-core-3.1.0.RELEASE.jar
  • spring-security-config-3.1.0.RELEASE.jar
  • spring-security-web-3.1.0.RELEASE.jar
3) Добавляем в web.xml следующие строки:
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
- для инициализации контекста спринга в целом
    <context-param>
        <param-name>
            contextConfigLocation
            </param-name>
        <param-value>
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param> 
- для установки пути к файлу конфигурации Spring
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter> 
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 
- для добавления фильтра Spring Security на все страницы

4) Создаем в WEB-INF/ файл конфигурации спринга spring-security.xml и добавляем в него:

<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">


    <!--Public resources -->
    <http pattern="/js/**" security="none"/>
    <http pattern="/style/**" security="none"/>
    <http pattern="/img/**" security="none"/>

    <http pattern="/login.jsp" security="none"/> 
    <http auto-config="true" access-denied-page="/login.jsp?accessDeniedError=1">
        <intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN
" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>

    <authentication-manager>
        <authentication-provider >
            <password-encoder hash="md5" />
            <user-service>
                <user name="test" password="098f6bcd4621d373cade4e832627b4f6" authorities="ROLE_USER,ROLE_ADMIN" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
    <beans:bean id="loginSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler" >
        <beans:property name="defaultTargetUrl" value="/index.jsp"/>
        <!--beans:property name="redirectStrategy" ref="defaultRedirectStrategy"/-->
    </beans:bean>
    <beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" >
        <beans:property name="defaultFailureUrl" value="/login.jsp?loginError=1" />
    </beans:bean>
</beans:beans>
Что в приведенном выше конфиге делается:
  • Устанавливается страница, отображаемая если на запрошенный ресурс не хватает прав у пользователя: login.jsp?accessDeniedError=1
  • Устанавливается страница, на которой будет размещена форма для ввода логина / пароля: login.jsp (на неё идет редирект если пользователь ещё не авторизован). Эта страница будет, естественно, доступна не авторизованным пользователям.
  • Устанавливается страница, куда идет редирект при неуспешной авторизации: login.jsp?loginError=1
  • Устанавливается страница, на котороую идет редирект после успешной авторизации: index.jsp
  • Пользователи задаются прямо в конфигурации, создается один пользователь с логином / паролем test/test (пароль захэширован по алгоритму md5) и ролями USER и ADMIN
  • Устанавливается путь, по которому размещается обработчик авторизации: j_spring_security_check (обработчик будет размещен спрингом автоматически, поэтому без разницы, какой урл указывать, главное чтобы он не конфликтовал с уже существующими)
  • Устанавливается ограничение на доступ ко всем страницам, кроме login.jsp, позволяющее иметь к этой странице доступ только пользователям с ролью USER или ADMIN
  • Доступ к всем элементам директорий js, style и img делается открытым (не требующим аутентификации)
5) Создаем форму авторизации. В ней указываем в качестве action="j_spring_security_check", а поля имени пользователя и пароля называем, соответственно, "j_username" и "j_password".
6) Разавторизация может осуществляется кодом:
SecurityContextHolder.getContext().setAuthentication(null);
Правда, этот код нельзя вызывать на login.jsp, т.к. она помечена как незащищенная, и, следовательно, на ней контекст безопасности недоступен (такой вызов попросту ни к чему не приведет). Чтобы решить эту проблему, понадобится следующая конфигурация:
     <!--Public resources -->
    <http pattern="/js/**" security="none"/>
    <http pattern="/style/**" security="none"/>
    <http pattern="/img/**" security="none"/>
    <!-- login.jsp is under spring security control, but is accessible anonimously -->
    <http pattern="/login.jsp">
        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>
    <http auto-config="true" access-denied-page="/login.jsp?accessDeniedError=1">
        <intercept-url pattern="/**" access="ROLE_USER" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>
В прочем, разавторизацию можно сделать и проще, перейдя на URL "/j_spring_security_logout" (этот URL можно при желании переопределить в конфиге). После перехода на него произойдет разавторизация и редирект на страницу логина. 

java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.getLocalName(Lorg/w3c/dom/Node;)Ljava/lang/String;

Проблема:
При попытке задеплоить на Томкат веб-приложение, использующее Spring Security, вываливается исключение:
java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.getLocalName(Lorg/w3c/dom/Node;)Ljava/lang/String;
Причина:
Spring Security 3.x используется с Spring 2.x.

Решение:
Заменить библиотеки Spring 2.x на Spring 3.x.

org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'authentication-provider'

Проблема:
При попытке задеплоить на Томкат веб-приложение, использующее Spring Security, вываливается исключение, ругающееся на xml-файл конфигурации Спринга, точнее, на вложенный в <beans> тег <authentication-provider>:
org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'authentication-provider'
Причина:
При переходе версий Spring Security с 2.x на 3.x изменилась схема конфигурационного файла, теперь тег <authentication-provider> должен быть вложен в <authentication-manager>.

Решение:
Поправить конфигурацию спринга, обернув <authentication-provider> в <authentication-manager>:

    <authentication-manager>
        <authentication-provider >
            <user-service>
                <user name="test" password="test" authorities="ROLE_USER,ROLE_ADMIN" />
                <user name="alex" password="847c6f184197dc1545d9891d42814a7d" authorities="ROLE_USER" />
                <user name="tim" password="0513111ff330e25c631b5d3e9c0a4aae" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'http'

Проблема:
При попытке задеплоить на Томкат веб-приложение, использующее Spring Security, вываливается исключение, ругающееся на xml-файл конфигурации Спринга, точнее, на вложенный в <beans> тег <http>:
org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'http'
Решение:
Подключить в проект библиотеку spring-security-config.jar, содержащую схемы для конфигурационных файлов.

суббота, 7 января 2012 г.

GUI SNV-клиент для Debian: rapidsvn

rapidsvn - вполне удобный snv-клиент с графическим интерфейсом. 

1C-Bitrix на Debian

Для установки битрикса с кодировкой UTF-8 на установленный из репозитория Debian Apache2+php нужно изменить следующие настройки:
1. /etc/apache2/sites-available/default: в блоке <Directory /var/www/> установить:
AllowOverride All
2. /etc/php5/apache2/php.ini: раскомментировать и отредактировать следующие значения:
mbstring.internal_encoding = UTF-8
mbstring.func_overload = 2

вторник, 3 января 2012 г.

Настройка тачпада Synaptics в Debian + XFCE

В Гноме тап по тачпаду "из коробки" работал как клик левой кнопкой мыши, в XFCE же почему-то - нет, что собственно и стало поводом поковыряться в конфигах иксов с целью настройки тачпада. Как ни странно, двухпальцевый скроллинг сразу же работал и там, и там (чего не было в Ubuntu, где приходилось ставить Synaptics`овскую утилиту для настройки), а вот поведение тапа двумя пальцами меня тоже не устраивало - оно воспринималось как правый клик, а мне хотелось бы чтобы как в винде - как клик центральной кнопкой, удобно открывать ссылки в браузере на новой вкладке =).
За основу была взята инструкция отсюда: http://www.crunchbang.ru/viewtopic.php?id=938, большое спасибо за неё автору. Я добавил в неё лишь двухпальцевый скроллинг, настройку тапа двумя пальцами и откалибровал скорость перемещения курсора.
Во-первых, убеждаемcя, что у нас действительно тачпад Synaptics:

root@eeedebian:/home/aspirin# egrep -i 'synap|alps|etps' /proc/bus/input/devices
N: Name="SynPS/2 Synaptics TouchPad"
Нам понадобиться модуль synaptics для иксов, поэтому он тоже должен быть установлен:
root@eeedebian:/home/aspirin# aptitude search xserver-xorg-input-synaptics
i A xserver-xorg-input-synaptics    - Synaptics TouchPad driver for X.Org server
p   xserver-xorg-input-synaptics-de - Synaptics TouchPad driver for X.Org server
В этот пакет также входит удобная утилита для мониторинга событий тачпада synclient, которая в дальнейшем пригодится.
Теперь идем в /etc/X11/xorg.conf. Если у Вас его нет - как его сгенерировать, я писал тут: http://barbitoff.blogspot.com/2011/06/touchscreen-egalax-eeepc-t101mt-debian.html, под пунктом 2. Там же написано, как перезапускать искы.
В xorg.conf добавляем следующие строчки (секции, которые уже имеются, добавлять нет необходимости - можно просто вставить в них ещё одну строчку):
Section "ServerLayout"
     InputDevice "Synaptics Touchpad" "SendCoreEvents"
EndSection
...
Section "Module"
Load "synaptics"
EndSection
...
Section "InputDevice"
  Identifier      "Synaptics Touchpad"
  Driver          "synaptics"
#  Option          "SendCoreEvents"        "true"
  Option          "Device"                "/dev/psaux"
  Option          "Protocol"              "auto-dev"
  Option          "HorizEdgeScroll"       "0" # выключаем скроллинг границами тачпада
  Option          "VertEdgeScroll"       "0" # выключаем скроллинг границами тачпада
  Option    "VertTwoFingerScroll" "1" # включаем двухпальцевый скроллинг
  Option  "HorizTwoFingerScroll" "1" # включаем двухпальцевый скроллинг
  Option  "EmulateTwoFingerMinW" "8" # если толщина больше 8 - значит 2 пальца (мой один палец вообще воспринимается не больше, чем 6)
  Option  "EmulateTwoFingerMinZ" "60" # при 70 иногда "проскальзывает", воспринимая 2 пальца за один
  Option          "SHMConfig"             "true"
  Option          "Emulate3Buttons"   "on"
  Option          "LeftEdge"      "1700"
  Option          "RightEdge"     "5300"
  Option          "TopEdge"       "1700"
  Option          "BottomEdge"    "4200"
  Option          "FingerLow"     "35"
  Option          "FingerHigh"    "40"
  Option          "MaxTapTime"    "180"
  Option          "MaxTapMove"    "220"
  Option          "VertScrollDelta" "100"
  Option          "HorizScrollDelta" "50"
  Option          "MinSpeed"      "0.24"
  Option          "MaxSpeed"      "0.48"
  Option          "AccelFactor" "0.00100"
  Option          "TapButton1" "1" #тап одним пальцем -> левый клик
  Option          "TapButton2" "2" #тап двумя пальцами -> центральный клик
  Option          "TapButton3" "3" #эх, жаль, что при эмуляции многопальцевости 3 пальца почему-то не детектируются, а то можно было бы на 3 пальца навесить правую кнопку мыши
EndSection


Собственно, что настроено вышеуказанным конфигом:
  • Выключена прокрутка краями тачпада, включена прокрутка двумя пальцами
  • Скорость движения курсора настраивается параметрами MinSpeed и MaxSpeed, тут уж, как говорится, на вкус и цвет.. Мне нравится, чтобы курсор бегал пошустрее (наверное из-за мыши с 3000dpi), так что я эти параметры увеличил.
  • Опция TapButton1 включила заветный левый клип по тапу одним пальцем
  • Опцией TapButton2 я включил нажатие центральной кнопки по тапу двумя пальцами. Тап 3 пальцами к сожалению не заработал, так как у моего тачпада родной поддержки многопальцевости видимо нет, а при эмуляции драйвер распознает только 2 пальца. 
Кстати об эмуляции: необходимость её использования определить просто: запускаем synclient -m 100, и нажимаем по тачпаду несколькоми пальцами стразу. Если в столбце "f" все время единица - значит тач не умеет определять многопальцевое нажатие. В таком случае продолжаем нажимать на тач то одним, то двумя пальцами, и смотреть на изменение значений в столбцах "w" (ширина нажатия) и "z" (сила нажатия). Наша задача - определить порог по ширине и силе нажатия, отличающий нажатие одного пальца от нажатий двух. Причем важнее всего именно параметр "w", так как сила может быть примерно одинаковой для обоих случаев. Для моих пальцев "w" при нажатии одним пальцем равняется 5, максимум 6, а двумя - не менее 10. Поэтому я взял на всякий случай пороговое значение 8, и присвоил его опции "EmulateTwoFingerMinW". В качестве "EmulateTwoFingerMinZ" я взял 60, хотя порой можно и одним пальцем с такой силой тыкнуть, но ложных срабатываний это не вызывает. А вот установка значения, скажем, 70, приводит иногда к тому, что двухпальцевый скроллинг воспринимается просто как перемещение курсора, если нажать с недостаточной силой. В принципе, при такой эмуляции многопальцевости не составило бы труда определять и нажатия тремя пальцами, установив соответствующий порог ширины нажатия, но программисты synaptics не стали с этим заморачиваться, а жаль.

После изменения конфига перезапускаем иксы и пробуем.

По всем опциям настройки тачпада есть неплохое описание в man synaptics, ещё пара полезностей (как, например, отключение тачпада при наборе на клавиатуре, что мне, лично, не нужно) достаточно доступно описана тут: http://www.crunchbang.ru/viewtopic.php?id=938, так что успехов =).