среда, 22 октября 2008 г.

Проблема логина через https в Spring Security 2.0

Довольно тривиальная задача, как мне казалось, сделать логин на https-соединении с дальнейшим редиректом на страницу доступную по обычному http-каналу. Для реализации такого решения использовался Spring Security 2.0.4. Однако, все оказалось не так просто.
Для начала приведу свою настройку security-контекста:

<sec:http auto-config="true">
<sec:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
<sec:intercept-url pattern="/index.jsp" access="ROLE_PLAYER" requires-channel="http"/>
<sec:form-login login-page="/login.jsp" default-target-url="/index.jsp" />
</sec:http>

Конфигурация правильная, только вот редирект не работает. Проблема в том, что после успешной аутентификации, меня перебрасывает обратно на login.jsp.

Воспользовашись HttpWatch-ем, я выяснил, что проблема в том, что при переходе, допустим, с линка https://localhost:8443/login.jsp на линк http://localhost:8080/index.jsp, jsessionid передавалась в куке через http-заголовок, а не через урл, как полагается в этом случае. Поэтому Spring Security не видел ранее созданной сесси и создавал свою. Кстати, по умолчанию, после успешной аутентификации он создает новую сессию, дабы предотвратить атаку Session Fixation.

Я завел на это багу http://jira.springframework.org/browse/SEC-1019. Не знаю, когда она будет закрыта, думаю, что не скоро. Поэтому могу предложить свое, временное, решение этой проблемы.
В конфигурации security-контекста пишем:

<sec:http entry-point-ref="authEntryPoint">
<sec:anonymous/>
<sec:port-mappings>
<sec:port-mapping http="8080" https="8443"/>
</sec:port-mappings>
<sec:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
<sec:intercept-url pattern="/index.jsp" access="ROLE_PLAYER" requires-channel="http"/>
</sec:http>

<bean id="authEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>

<bean id="authFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<sec:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
<property name="defaultTargetUrl" value="/"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="targetUrlResolver">
<bean class="ru.someone.security.ExTargetUrlResolverImpl">
<property name="url" value="/index.jsp"/>
</bean>
</property>
</bean>

<sec:authentication-manager alias="authenticationManager"/>

Столько xml-я пришлось написать лишь для того, чтобы использовать свою реализацию org.springframework.security.ui.TargetUrlResolver, по-другому никак. Вот собственно и сама реализация этого интерфейса:

package ru.someone.security;

import javax.servlet.http.HttpServletRequest;
import org.springframework.security.Authentication;
import org.springframework.security.ui.TargetUrlResolverImpl;
import org.springframework.security.ui.savedrequest.SavedRequest;

public class ExTargetUrlResolverImpl extends TargetUrlResolverImpl {

private String url;

@Override
public String determineTargetUrl(SavedRequest savedRequest, HttpServletRequest request,
Authentication auth) {
String sessionId = request.getSession().getId();
return url + ";jsessionid=" + sessionId;
}

public void setUrl(String url) {
this.url = url;
}
}

3 комментария:

Slonopotamus комментирует...

Идентификатор сессии в url несекьюрно (session-fixation и утекание через referrer на внешних ссылках) и ненадёжно, т.к. на каждой ссылке надо не забывать прогнать их через добавлятор идентификатора.

К тому же, как вам написали в баге, они это делают.

Никита Кокшаров комментирует...

Ну если говорить о несекьюрности, то можно начать с того, что переключение на http уже не безопасно само по себе. Какая разница через что передавать sessionid, если я возьму снифер и выловлю его... А по поводу баги, я знаю, что они так и делают, только вот не работает ничего, потому что в HttpRequest.redirectUrl не занимается выставлением jsessionid при переключении каналов... Это вроде как нелепая причина, с их стороно лишь бы не фиксить, а фикс там простой. А что такое "добавлятор идентификатора"?

Анонимный комментирует...

Вам же объяснили, что через реферер. И без всякого сниферра утечет.