Автоматизировать вход на сайт с помощью Spring Boot (Spring Security) и LDAP - PullRequest
0 голосов
/ 16 февраля 2019

Я работаю над проектом Spring Boot, в котором для аутентификации используется LDAP в Spring Security.

Мне нужно автоматизировать вход в систему после того, как пользователь перейдет на страницу входа, основываясь на ролях в группе LDAP, предоставленной в Spring.Безопасность.

Если пользователь играет какую-либо роль в группе, упомянутой в LDAP, он должен перенаправить на соответствующую страницу после входа в систему.(то есть page1 в моем примере).

Я искал 2 дня подряд для любой онлайн-документации или примера, но тщетно.Все, что я мог найти, - это использовать jdbcDataSource или жесткое кодирование имени пользователя и пароля в Controller, а затем проверять его при входе в систему или через Spring с помощью web.xml.Но не через LDAP.Любая помощь будет очень полезна.

Вот так выглядит мой Spring Security XML :

<?xml version="1.0" encoding="UTF-8" ?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security.xsd
                                 http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/logout" access="permitAll" />
        <intercept-url pattern="/webjars/**" access="permitAll" />
        <intercept-url pattern="/page1" access="hasAnyRole('GP1','GP2')" />
        <intercept-url pattern="/page2" access="hasAnyRole('GP1','GP2')" />
        <intercept-url pattern="/page3" access="hasAnyRole('GP1','GP2')" />
        <intercept-url pattern="/**" access="permitAll" />

        <form-login default-target-url="/page1" login-page="/login"
            always-use-default-target="true" />
        <access-denied-handler error-page="/403.html" />
        <csrf disabled="true" />
        <logout logout-url="/logout" />
    </http>

    <authentication-manager alias="authenticationManager"
        erase-credentials="false">
        <authentication-provider ref="ldapAuthProvider" />
    </authentication-manager>

    <ldap-server id="contextSource" url="ldap://url"
        manager-dn="mymanagerdn" manager-password="mymanagerpswd" />

    <beans:bean id="ldapAuthProvider"
        class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
        <beans:constructor-arg>
            <beans:bean id="bindAuthenticator"
                class="org.springframework.security.ldap.authentication.BindAuthenticator">
                <beans:constructor-arg ref="contextSource" />
                <beans:property name="userSearch" ref="userSearch" />
            </beans:bean>
        </beans:constructor-arg>
        <beans:constructor-arg>
            <beans:bean
                class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
                <beans:constructor-arg ref="contextSource" />
                <beans:constructor-arg value="myDCvalues" />
                <beans:property name="searchSubtree" value="true" />
                <beans:property name="ignorePartialResultException"
                    value="true" />
                <beans:property name="groupSearchFilter" value="(member={0})" />
            </beans:bean>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id="userSearch"
        class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
        <beans:constructor-arg index="0"
            value="myDCvalues" />
        <beans:constructor-arg index="1"
            value="(sAMAccountName={0})" />
        <beans:constructor-arg index="2" ref="contextSource" />
        <beans:property name="searchSubtree" value="true" />
    </beans:bean>

</beans:beans>

Мой WebController :

package com.myPackage;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Controller
public class WebController extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/page1").setViewName("page1");
        registry.addViewController("/page2").setViewName("page2");
        registry.addViewController("/page3").setViewName("page3");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/403").setViewName("error/403");
    }

    @GetMapping("/page1")
    public String page1(HttpSession session) {
        return "page1";
    }

    @GetMapping("/page2")
    public String page2(HttpSession session) {
        return "page2";
    }

    @GetMapping("/page3")
    public String page3(HttpSession session) {
        return "page3";
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/403")
    public String error403() {
        return "error/403";
    }

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("templates/");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    private String getCredentials() {
        String credential = null;

        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        credential = userDetails.getUsername().toString();

        return credential;
    }

}

1 Ответ

0 голосов
/ 18 февраля 2019

Для вашего удобства этот ответ поставляется с полным и рабочим образцом , включая сервер LDAP, заполненный пользователями и группами, и интеграционным тестом, так что вы можете запустить эти тесты самостоятельно.

Предположим, у вас есть следующий пользователь в LDAP

dn: cn=marissa,ou=Users,dc=test,dc=com
changetype: add
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: marissa
userPassword: koala
uid: 20f459e0-e30b-4d1f-998c-3ded7f769db1
mail: marissa@test.com
sn: Marissa

Имя пользователя Марисса и пароль Коала .

Давайте начнемс тестовым примером:

    @Test
    @DisplayName("ldap login works")
    void doLogin() throws Exception {
        mvc.perform(
            MockMvcRequestBuilders.post("/login")
                .param("username", "marissa")
                .param("password", "koala")
                .with(csrf())
        )
            .andExpect(status().is3xxRedirection())
            .andExpect(authenticated())
        ;
    }

Из этого теста мы можем сделать вывод, что

  1. LDAP использует форму входа в систему, имя пользователя / пароль
  2. Форма имеет защиту CSRF

Итак, давайте настроим ваше приложение Spring Boot, используя конфигурацию Java

Классический пример файла, SecurityConfig.java

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

Конфигурация безопасности не изменяется.

  1. Мы хотим, чтобы пользователи были полностью аутентифицированы
  2. Мы хотим использовать форму входа в систему
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest()
                .fullyAuthenticated()
                .and()
            .formLogin()
        ;
    }

Вот и все, затем мы настраиваем LDAP, снова вВаш SecurityConfig.java мы делаем это, вызывая AuthenticationManagerBuilder.Это bean-компонент, который настраивает Spring Security.Таким образом, мы можем получить к нему доступ, используя @Autowired

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .contextSource()
                    .url("ldap://localhost:389")
                    .managerDn("cn=admin,dc=test,dc=com")
                    .managerPassword("password")
                    .and()
                .userSearchBase("ou=Users,dc=test,dc=com")
                .userSearchFilter("cn={0}")
                .groupSearchBase("dc=test,dc=com")
                .groupSearchFilter("member={0}")
        ;
    }

и все.Теперь я использовал некоторый код, который я написал из проекта Cloud Foundry UAA, для создания LDAP-сервера в памяти для моих интеграционных тестов.

Поэтому, когда запускается фиктивный интеграционный тест MVC, он запускаетсясервер LDAP для запуска.

Это действительно так просто.Теперь вы можете расширить этот образец, чтобы сопоставить группы LDAP с полномочиями Spring Security.

Образец LDAP доступен в моем репозитории сообщества: https://github.com/fhanik/spring-security-community.git

...