barbitoff programmer`s blog

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

вторник, 9 октября 2012 г.

Spring Security 3.1: получение списка залогиненных пользователей

Задача:

Получить список залогиненных пользователей (например, чтобы разлогинить некоторых из них).

Решение:

Для решения этой задачи можно воспользоваться реестром пользовательских сессий, который используется Spring Security, в частности, для контроля множественного входа под одним логином. Чтобы реестр заполнялся и к нему можно было получить доступ из собственного кода, нужно (если, конечно, у Вас уже не используется контроль множественного входа):
  1. В web.xml добавить слушателя:
    <listener>
      <listener-class>
    org.springframework.security.web.session.HttpSessionEventPublisher
      </listener-class>
    </listener>
  2. В конфигурацию Spring Security добавить:


    <!-- Задаем точку входа и страницу запрета доступа, обязательно
      -- отключаем auto-config, чтобы определить свой фильтр для входа
      -- по логину/паролю
      -->
    <http auto-config="false" access-denied-page="/login.jsp?accessDeniedError=1"
              entry-point-ref="authenticationProcessingFilterEntryPoint">

            <custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordFilter" />
         
    <!-- Далее идут правила доступа -->
            <intercept-url ... />
    ...  
    <!-- Указываем ссылку на бин для session-managment`а -->
            <session-management session-authentication-strategy-ref="sas"/>
    <!-- Конфигурация выхода обыкновенная -->
            <logout delete-cookies="JSESSIONID" logout-url="/j_spring_security_logout"/>
    </http>

    <!-- Конфигурируем точку входа в приложение -->
    <beans:bean id="authenticationProcessingFilterEntryPoint"
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:property name="loginFormUrl" value="/login.jsp" />
    <beans:property name="forceHttps" value="false" />
    </beans:bean>

    <!-- Конфигурируем реестр сессий -->
    <beans:bean id="sessionRegistry"
    class="org.springframework.security.core.session.SessionRegistryImpl" />

    <!-- Конфигурируем бин стратегии контроля сессий. Не ограничиваем
      -- множественность входа (нам это сейчас не нужно, по этой же причине
      -- мы не использовали фильтр ConcurrentSessionFilter)
      -->
    <beans:bean id="sas" class=
    "org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
    <beans:constructor-arg ref="sessionRegistry" />
    <beans:property name="maximumSessions" value="-1" />
    </beans:bean>

    <!-- Конфигурируем фильтр входа по логину / паролю, задавая ссылку на стратегию,
      -- а также ссылки на бины обработчиков успешного / неуспешного входа
      -->
    <beans:bean id="usernamePasswordFilter" class=
                "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <beans:property name="sessionAuthenticationStrategy" ref="sas" />
    <beans:property name="authenticationManager" ref="authenticationManager" />
    <beans:property name="authenticationFailureHandler" ref="loginFailureHandler"/>
    <beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"/>
    </beans:bean>

    <!-- Менеджер аутентификации. Тут все стандартно, задается один какой-то провайдер
      -- и для стандартного провайдера задается какой-то UserService
      -->
    <authentication-manager alias="authenticationManager">
    <authentication-provider ref="..."/>
    <authentication-provider user-service-ref='...'>
    <password-encoder hash="md5" />
    </authentication-provider>
    </authentication-manager>

    <!-- Обработчики успешного / неуспешного логина. Стандартные -->
    <beans:bean id="loginSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler" >
    <beans:property name="defaultTargetUrl" value="/index.jsp"/>
    </beans:bean>

    <beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" >
    <beans:property name="defaultFailureUrl" value="/login.jsp?loginError=1" />
    </beans:bean>

  3. Теперь получить реестр и список активных принципалов в коде можно так:
    import org.springframework.security.core.session.SessionRegistry;
    import org.springframework.web.context.support.WebApplicationContextUtils;

    ...

    ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
    SessionRegistry sReg = (SessionRegistry) ac.getBean("sessionRegistry");
    for(Object principal: sReg.getAllPrincipals())
         System.out.println("Principal: "+principal.toString());

PS Надо, пожалуй, озаботиться подсветкой синтаксиса в блоге =)

Spring Security 3.1: AuthenticationProcessingFilterEntryPoint

В Spring Security 3.1 нет AuthenticationProcessingFilterEntryPoint, в отличие от версий 3.0.х, вместо него есть аналогичный класс org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint. Инициализируется через spring security namespace он совершенно также:

<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
  <beans:property name="loginFormUrl" value="/login.jsp" />
  <beans:property name="forceHttps" value="false" />
</beans:bean>

пятница, 5 октября 2012 г.

php: установка заголовков запроса при загрузке данных по http с помощью функции file_get_contents()

Чтобы установить какой-нибудь заголовок http-запроса при загрузке данных по http функцией file_get_contents(), нужно использовать третий параметр этой функции - $context. Например, чтобы установить User-Agent как у 15ого Firefox`а, нужно:
$opts = array('http'=>array('header' => "User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1\r\n"));
$context = stream_context_create($opts);
$html = file_get_contents($link,false,$context);
А то некоторые сайты, например, без этого плюются 500ой ошибкой и не дают себя по-человечески сграбить =)
Warning: file_get_contents(http://***.ru/***): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error

среда, 3 октября 2012 г.

cmd: смонтировать папку как локальный диск

Чтобы смонтировать, например, папку D:\a\b\c как диск Q:, нужно:
SUBST Q: D:\a\b\c

away3d: двусторонний материал и освещение

Установив у материала свойство bothSides=true, можно добиться, чтобы обе стороны граней, на которые материал наложен, были видимыми (в противном случае одна будет видимой, другая - прозрачной). Однако, если к материалу применено освещение (установлено свойство lightPicker), вторая сторона будет некорректно вести себя по отношению к свету. Т.е., например, если освещение падает только со стороны наблюдателя, одна сторона грани будет корректно освещена, в вот вторая будет казаться неосвещенной.
Дело в том, что освещение грани рассчитывается исходя из угла между нормалью к ней и направлением света. При этом нормаль у грани одна на обе стороны, и для одной стороны она оказывается "выходящей" навстречу наблюдателю, и, значит, освещению, а для второй - "входящей", сонаправленной с направлением света.
Варианта выхода из данной ситуации 2: либо научить away3d самостоятельно инвертировать нормаль при расчете освещенности обратной стороны, либо дублировать все грани фигуры, разворачивая их нормали в обратную сторону. Последнее делается просто, воспользовавшись away3d.tools.helpers.MeshHelper`ом:
var mesh:Mesh = new Mesh(geometry, material);
var duplicateMesh =  new Mesh( geometry.clone(), material);
MeshHelper.invertFaces(duplicateMesh);
Первый вариант сложнее, я пока не копал в эту сторону, хотя с целью уменьшения числа граней и экономии ОП, пожалуй, стоит попробовать. 

вторник, 2 октября 2012 г.

Mint с Mate: как убрать "Мой компьютер" и "Домашняя папка пользователя" с рабочего стола

Чтобы убрать значки "Мой компьютер" и "Домашняя папка пользователя" с рабочего стола, нужно:
  1. Открыть меню программ, зайти в "Параметры" -> "Внешний вид рабочего стола"
  2. Снять соответствующие галочки

понедельник, 1 октября 2012 г.

Xftp 4: кодировка имен файлов

Чтобы вместо русских букв в именах файлов при подключении к Linux-хостам не появлялись кракозябры, нужно:
File -> Properties -> Options -> Поставить галку "Use UTF-8 encoding"