вторник, 2 августа 2011 г.

Spring 3: custom authentication by Request header

Очередная задача.
Предположим, аутентификацию пользователя производит некая система, (например, сервер Апач), который устанавливает в заголовок запроса REMOTE_USER уникальное имя пользователя.
Как аутентифицировать пользователя, используя Spring-Security?

Признаюсь, сам с лёту не смог решить эту проблему.
Пришлось задать вопрос на stackoverflow.com, быстро получил ответ:

you'll need to have an auth provider. If the user name is being supplied through an HTTP header and you're just going to trust it, you're actually in what's called a pre-authenticated case (i.e., there's something else that's done the authentication step for you). The Spring Security documentation has a whole chapter on this using Siteminder as an example: just change the header name and it should work. (Well, you'll also need a user details service, so that you can map from the authenticated user to the set of authorities that they are granted, but that's a whole 'nother story.)
 

Конфигурация :
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns="http://www.springframework.org/schema/security"
             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-3.0.xsd
   http://www.springframework.org/schema/security
   http://www.springframework.org/schema/security/spring-security-3.0.xsd">

  <http use-expressions="true" auto-config="true">
    <custom-filter position="PRE_AUTH_FILTER" ref="remoteUserFilter"/>
    <intercept-url pattern="/admin/main.action" access="hasRole('ADMIN')"/>
    <intercept-url pattern="/admin/updateMsgTmplCache.action" access="hasRole('PK')"/>
    <intercept-url pattern="/admin/**" access="isAuthenticated()"/>
  </http>

  <beans:bean id="remoteUserFilter"
              class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <!--<beans:property name="principalRequestHeader" value="REMOTE_USER"/>-->
    <beans:property name="principalRequestHeader" value="REMOTE_USER"/>
    <beans:property name="authenticationManager" ref="authenticationManager"/>
  </beans:bean>

  <authentication-manager alias="authenticationManager">
    <authentication-provider ref="preauthAuthProvider"/>
  </authentication-manager>

  <beans:bean id="preauthAuthProvider"
        class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <beans:property name="preAuthenticatedUserDetailsService">
      <beans:bean id="userDetailsServiceWrapper"
                  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
        <beans:property name="userDetailsService" ref="userDetailsService"/>
      </beans:bean>
    </beans:property>
  </beans:bean>

  <beans:bean id="userDetailsService" class="ee.security.RemoteUserDetailsServiceImpl"/>

</beans:beans>


Остаётся написать сервис RemoteUserDetailsServiceImpl, который загружает данные пользователя и его роли по имени (REMOTE_USER), примерно так:
@Service
public class RemoteUserDetailsServiceImpl implements UserDetailsService
{
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException
  {
    // ToDo: here must be a real logic to load user data.
    System.out.println("Authenticating user " + username);
    return new UserDetailsImpl( username );
  }
}

Комментариев нет:

Отправить комментарий