Администратор по умолчанию (Spring 3, Spring Security) - PullRequest
4 голосов
/ 06 января 2012

Это вопрос безопасности Spring.

В моем приложении объект User является объектом домена.Пользователи будут зарегистрированы и будут входить с учетными данными, хранящимися в базе данных.Мой доменный объект User содержит реализацию для поддержки объекта Spring UserDetails.

Проблема в том, что мне нужна возможность войти в приложение еще до того, как будет создан первый пользователь.Другими словами, мне нужно войти как 'admin', чтобы создать пользователя 'admin'.

Чтобы убедиться, что моя установка Spring работает, я в настоящее время возвращаю пользователя с жестким кодом из SpringSecurityUserDetailsServiceImpl.loadUserByUsername (String userName).

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {

    User user=null;
    try {
        if("admin".equalsIgnoreCase(userName)) {
            user=new User();
            user.setUserName("ADMIN");
            user.setPassword("adsf"); // assume there's a hash of a true password here
            user.setStatus(UserStatus.ACTIVE);
            user.setAccessLevel(UserAccessLevel.ADMINISTRATOR);
        } else {
            //user = userDAO.getUserByUserName(userName);

        }

    } catch(Throwable t) {
        throw new UsernameNotFoundException("Unable to locate User with user name \"" + userName + "\".", t);
    }

    return user;
}

Это работает, так что теперь я ищу правильный способ сделать это.Можно было бы определить эти учетные данные администратора по умолчанию в файле свойств и прочитать этот файл свойств в loadUserByUsername (String userName), чтобы создать объект пользователя admn.Однако я надеюсь, что есть способ сделать это в конфигурации xml Spring Security.Я попытался security:user name="admin" password="admin" authorities="ADMINISTRATOR", но это, очевидно, не работает, когда у вас есть security:authentication-provider user-service-ref="customUserDetailsService"

Мой spring-security.xml

<security:http auto-config="true" use-expressions="true" access-denied-page="/denied">
<security:intercept-url pattern="/login.html" access="permitAll"/>
<security:intercept-url pattern="/style/**" access="permitAll"/>
<security:intercept-url pattern="/user**" access="hasRole('ADMINISTRATOR')"/>
<security:intercept-url pattern="/**" access="hasRole('AUTHOR')"/>

<security:form-login    login-page="/login.html"
                        login-processing-url="/j_spring_security_check" 
                        authentication-failure-url="/login.html?failedAttempt=true"
                        default-target-url="/home.html"/>

<security:logout        invalidate-session="true"
                        logout-success-url="/login"
                        logout-url="/logout"/>
                        </security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="customUserDetailsService">       
        <security:password-encoder ref="passwordEncoder"/>
    </security:authentication-provider>
</security:authentication-manager>

<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>


<bean id="customUserDetailsService" class="com.modelsite.services.impl.SpringSecurityUserDetailsServiceImpl"/>

Итак, вопрос: как определить администратора по умолчаниюпользователь, который может войти и делать вещи.Обратите внимание, я не хочу обрабатывать это с помощью импорта sql во время установки.

Ответы [ 4 ]

3 голосов
/ 06 января 2012

У вас может быть несколько поставщиков аутентификации:

  • Используйте первый, как вы уже сделали.
  • Добавьте секунду с фиксированным именем, паролем и ролью для администратора.

(Порядок обоих провайдеров аутентификации важен; второй учитывается только в том случае, если аутентификация не обнаружена в первом.)

<security:authentication-manager>
    <security:authentication-provider user-service-ref="customUserDetailsService">       
        <security:password-encoder ref="passwordEncoder"/>
    </security:authentication-provider>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
        </security:user-service>
   </security:authentication-provider>
</security:authentication-manager>

@см. также: Могу ли я иметь несколько контекстов безопасности с пружинной защитой?

1 голос
/ 05 марта 2015

Лично для учетной записи администратора я не буду использовать базовую пользовательскую службу Spring Security, главным образом потому, что ей не хватает гибкости подхода управления пользователями на основе БД.На самом деле, вы, вероятно, не хотите, чтобы ваши учетные данные администратора устанавливались раз и навсегда, поскольку их можно угадать, украсть или просто забыть.быть введенным в действие для всех учетных записей, включая учетную запись администратора (при условии, что вы используете доверенную учетную запись электронной почты для восстановления пароля, но это разумное предположение).

Если конкретнее, мой подход заключается в следующем: я используюAuthenticationManager где я добавляю CustomUserDetailService

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="customUserDetailsService" >
            <password-encoder ref="passwordEncoder" />
        </authentication-provider>
    </authentication-manager>

    <b:bean id="passwordEncoder"
    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

, который является следующим

    @Service
    public class CustomUserDetailsService implements UserDetailsService{

        @Autowired
        @Qualifier("userDaoImpl")
        private UserDao userDaoImpl;

        @Override
        @Transactional
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
        {
            User user = userDaoImpl.loadByUsername(username);
            if (user != null)
                return user;
            else
                throw new UsernameNotFoundException(username + " not found.");
        }
    }

, это работает для всех пользователей, а не только для администратора.

Сейчас возникает проблема с полным функционалом учетной записи администратора при запуске приложения .Это достигается с помощью компонента инициализации , который должен выполняться при запуске, подробно описано в следующем

    @Component
    public class Initializer {

        @Autowired
        private HibernateTransactionManager transactionManager;
        @Autowired
        @Qualifier("userDaoImpl")
        private UserDao userDao;
        @Autowired
        private CredentialsManager credentialsManager;

        private String resetPassword = "makeItHardToGuess";
        private String adminUsername = "admin";


        @PostConstruct
        private void init()
        {
            //since we are executing on startup, we need to use a TransactionTemplate directly as Spring may haven't setup transction capabilities yet
            TransactionTemplate trxTemplate = new TransactionTemplate(transactionManager);
            trxTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    buildAdmin();
                }
            });
        }

        private void buildAdmin()
        {       
            //here I try to retrieve the Admin from my persistence layer
            ProfiledUser admin = userDao.loadByUsername(adminUsername);

            try
            {
                //If the application is started for the first time (e.g., the admin is not in the DB)
                if(admin==null)
                {   
                    //create a user for the admin                   
                    admin = new ProfiledUser();
                    //and fill her attributes accordingly
                    admin.setUsername(adminUsername);
                    admin.setPassword(credentialsManager.encodePassword(resetPassword));
                    admin.setAccountNonExpired(true);
                    admin.setAccountNonLocked(true);
                    admin.setCredentialsNonExpired(true);
                    admin.setEnabled(true);
                    admin.setEulaAccepted(true);

                    Authority authority = new Authority();
                    authority.setAuthority("ROLE_ADMIN");
                    admin.getAuthorities().add(authority);
                }
                //if the application has previously been started (e.g., the admin is already present in the DB)
                else
                {
                    //reset admin's attributes
                    admin.setPassword(credentialsManager.encodePassword(resetPassword));
                    admin.getAuthorities().clear();
                    Authority authority = new Authority();
                    authority.setAuthority("ROLE_ADMIN");
                    admin.getAuthorities().add(authority);
                    admin.setAccountNonExpired(true);
                    admin.setAccountNonLocked(true);
                    admin.setCredentialsNonExpired(true);
                    admin.setEnabled(true);
                }                   
                userDao.save(admin);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.out.println("Errors occurred during initialization. System verification is required.");
            }
        }
    }

. Обратите внимание, что аннотация @PostConstruct не гарантирует, что Spring предоставляет свои сервисы транзакций.доступно, поэтому мне пришлось управлять транзакцией самостоятельно.Пожалуйста, обратитесь к это для более подробной информации.

0 голосов
/ 16 августа 2015

ответ MaVVamaldo классный (уже дал мой +1 голос), кроме класса Initializer.Этот класс отлично подходит для инициализации базы данных, но он должен избегать жесткого кодирования учетных данных администратора, что небезопасно, поскольку исходный код может быть легко извлечен (и это то, чего в первую очередь просил исходный вопрос).

Лучшим решением IMHO будет загрузка хешированных учетных данных из файла .properties (доступ к которому вы ограничиваете с помощью chmod или аналогичного).чтобы это работало, вам нужно иметь следующее в вашем security-context.xml

    <authentication-manager>
        <authentication-provider>
            <password-encoder hash="sha">
                <salt-source user-property="username"/>    
            </password-encoder>
            <user-service properties="classpath:/users.properties" />
        </authentication-provider>
    </authentication-manager>

, где файл .properties выглядит так:

bob=4f393f2314f75650ee50844d8e4f016ab5b3468f,ROLE_ADMIN,enabled

соль - это имя пользователя, такВы вычисляете это по строке password{username}, как объяснено 1013 *.

0 голосов
/ 06 января 2012

Проблема в том, что мне нужна возможность войти в приложение еще до того, как будет создан первый пользователь.Другими словами, мне нужно войти в систему как 'admin', чтобы создать пользователя 'admin'.

Способ решения этой проблемы состоит в том, чтобы поместить несколько смартов в мой пользовательский класс UserDetailsService и/ или его класс DAO.Когда он обнаруживает, что он был запущен с пустыми таблицами сведений о пользователе (или чем-то еще), он инициализирует их некоторыми записями сведений о пользователе, которые он считывает из файла конфигурации.Это позволяет вам:

  • загрузить первоначальную учетную запись администратора в хранилище пользовательских данных вашей производственной системы
  • загрузить несколько тестовых учетных записей в хранилище пользовательских данных вашей тестовой системы для автоматизированного устройства и системыtesting.

Если это слишком много, просто создайте несколько операторов SQL, чтобы вставить соответствующие строки для команды admin, и запустите их с помощью интерактивной оболочки SQL вашей базы данных.


Встраивать учетную запись администратора в исходный код - плохая идея, потому что:

  • любой, кто может видеть ваш исходный код, может увидеть пароль (если вы не используете хеш),
  • это означает, чтовам нужно изменить и перекомпилировать код, чтобы изменить пароль, и
  • это означает, что вы будете использовать один и тот же пароль при тестировании и производстве (если вы не добавите это различие в ваш код какхорошо).

Все это поднимает вопросы безопасности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...