Пользовательская аутентификация и кодировка пароля Spring Security - PullRequest
52 голосов
/ 05 октября 2011

Есть ли учебник или у кого-нибудь есть указания, как сделать следующее с помощью Spring-Security?

Задача:

Мне нужно получить соль из моей базы данных для аутентификации имени пользователя и использовать ее для шифрования предоставленного пароля (со страницы входа в систему), чтобы сравнить его с сохраненным зашифрованным паролем (a.k.a. аутентифицировать пользователя).

дополнительная информация:

Я использую собственную структуру базы данных. Объект UserDetails создается с помощью пользовательского UserDetailsService, который, в свою очередь, использует пользовательский DAOProvider для получения информации из базы данных.

мой security.xml файл на данный момент:

<authentication-manager>
    <authentication-provider user-service-ref="userDetailsService">
    </authentication-provider>
</authentication-manager>

теперь, думаю, мне понадобится

        <password-encoder hash="sha" />

а что еще? Как мне сказать Spring Security использовать соль, предоставленную базой данных, для кодирования пароля?


редактировать

Я нашел Эта публикация SO является информативной, но недостаточной: если я определю источник соли в моем xml для использования кодировщиком паролей, например:

        <password-encoder ref="passwordEncoder">                
            <salt-source ref="saltSource"/>
        </password-encoder>

Мне нужно написать собственный SaltSource, чтобы использовать мою собственную соль. Но этого нельзя найти внутри объекта UserDetails. Итак ...

Альтернатива 1:

Могу ли я использовать пользовательскую реализацию UserDetails, которая может иметь свойство salt?

<beans:bean id="saltSource" class="path.to.MySaltSource"
    p:userPropertyToUse="salt"/>

и

@Service("userDetailsService") 
public class UserDetailsServiceImpl implements UserDetailsService {
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {

        // ...
        return buildUserFromAccount(account);
    }

    @Transactional(readOnly = true)

    UserDetailsImpl buildUserFromAccount(Account account){

        // ... build User object that contains salt property
}

пользовательский класс пользователя:

public class UserDetailsImpl extends User{

    // ...

    private String salt;

    public String getSalt() { return salt; }

    public void setSalt(String salt) { this.salt = salt; }
}

security.xml:

<authentication-manager>
    <authentication-provider user-service-ref="userDetailsService">
        <password-encoder hash="sha">                
        <salt-source ref="saltSource"/>
    </password-encoder>
    </authentication-provider>
</authentication-manager>

<beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource" p:userPropertyToUse="salt"/>


Альтернатива 2:

В противном случае мне пришлось бы ввести свой accountDAO в SaltSource, чтобы извлечь соль для данного userName из базы данных.

НО: как Spring Security называет SaltSource? Всегда с saltSource.getSalt(userDetails)?

Тогда мне просто нужно убедиться, что мой SaltSource использует userDetails.accountName на моем accountDAO для извлечения соли.


Edit2:

Только что узнал, что мой подход .. наследие .. :( Так что я думаю, что я просто буду использовать StandardPasswordEncoder (который мне еще предстоит выяснить, как именно использовать).

Кстати: я реализовал первый вариант с помощью пользовательского класса UserDetails, расширяющего класс User и просто добавляющего свойство соли, которое затем передается в SaltSource как userPropertyToUse, как это было предложено в посте SO, упомянутом в Edit 1. ...


РЕДАКТИРОВАТЬ 3:

Только что работает StandardPasswordEncoder, поэтому я оставлю здесь несколько указателей:

Используйте StandardPasswordEncoder для аутентификации:

<beans:bean id="encoder" 
    class="org.springframework.security.crypto.password.StandardPasswordEncoder">
</beans:bean>


<authentication-manager>
    <authentication-provider user-service-ref="userDetailsService">
        <password-encoder ref="encoder" />         
    </authentication-provider>
</authentication-manager>

Для этого требуется криптографический модуль spring-security в версии 3.1.0.RC? насколько я знаю. Не удалось найти репозиторий с версией 3.0. версия (хотя где-то там были перечислены версии, включающие 3.0.6 и так далее). Также в документации рассказывается о Spring Security 3.1, так что я решил, что я просто пойду с этим.

При создании пользователя (для меня это может сделать только админ), я просто использую

        StandardPasswordEncoder encoder = new StandardPasswordEncoder();
        String result = encoder.encode(password);

и я закончил.

Spring security случайным образом создаст соль и добавит ее в строку пароля перед сохранением в базе данных, поэтому столбец соли больше не требуется .

Однако можно также указать глобальную соль в качестве аргумента конструктора (new StandardPasswordEncoder("12345");), но я не знал, как настроить свою конфигурацию безопасности для получения этого значения из бина вместо предоставления статической строки с <constructor-arg name="secret" value "12345" />. Но я все равно не знаю, сколько это нужно.

Ответы [ 3 ]

34 голосов
/ 18 октября 2011

Я отмечу это как ответивший, поскольку я решил свою проблему, и никакие другие комментарии или ответы не были даны:

Редактировать 1 - Альтернатива 1 отвечает на оригинальный вопрос

НО Мне нужно было узнать, что настраиваемое получение пароля является устаревшим подходом, который больше не нужен в Spring Security 3.1, как я описал в

Редактировать 3 , где я оставил несколько советов о том, как использовать StandardPasswordEncoder для автоматических солей, которые хранятся с паролем.

4 голосов
/ 05 июля 2012

Для чего это стоит, я написал этот пост в блоге, подробно описав то, что вы описали: http://rtimothy.tumblr.com/post/26527448708/spring-3-1-security-and-salting-passwords

0 голосов
/ 02 июня 2013

Чтобы извлечь глобальную соль из боба, используйте язык выражений Spring или SpEL.

<beans:bean id="encoder" 
        class="org.springframework.security.crypto.password.StandardPasswordEncoder">
    <constructor-arg value="#{someotherBean.somePropertyWithAGetterMethod"/>
</beans:bean>
...