JHipster LDAP Аутентификация

1

Hey Overfloweens и JHipsters, я недавно пришел к выводу, что хочу попытаться связать свою безопасность JHipster с протоколом на сервере ldap, чтобы проверить подлинность в моем рабочем каталоге, в котором уже есть все пароли и имена пользователей. Тем не менее, я хочу продолжать использовать JHipster встроенную систему токенов, которая использует Spring-mvc. Я знаю, как сделать сервер ldap отдельно от JHipster, но я не знаю, как изменить файл SecurityConfiguration.java, чтобы сделать это реальностью. Любые советы были бы очень ценными.

Файл конфигурации безопасности:

package com.comcast.castit.config;

import javax.inject.Inject;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.web.authentication.RememberMeServices;

import com.comcast.castit.security.AjaxAuthenticationFailureHandler;
import com.comcast.castit.security.AjaxAuthenticationSuccessHandler;
import com.comcast.castit.security.AjaxLogoutSuccessHandler;
import com.comcast.castit.security.AuthoritiesConstants;
import com.comcast.castit.security.Http401UnauthorizedEntryPoint;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Inject
    private Environment env;

    @Inject
    private AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler;

    @Inject
    private AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler;

    @Inject
    private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

    @Inject
    private Http401UnauthorizedEntryPoint authenticationEntryPoint;

    @Inject
    private UserDetailsService userDetailsService;

    @Inject
    private RememberMeServices rememberMeServices;

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new StandardPasswordEncoder();
    }

    @Inject
    public void configureGlobal(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(
        passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/bower_components/**")
        .antMatchers("/fonts/**").antMatchers("/images/**")
        .antMatchers("/scripts/**").antMatchers("/styles/**")
        .antMatchers("/views/**").antMatchers("/i18n/**")
        .antMatchers("/swagger-ui/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling()
        .authenticationEntryPoint(authenticationEntryPoint).and()
        .rememberMe().rememberMeServices(rememberMeServices)
        .key(env.getProperty("jhipster.security.rememberme.key")).and()
        .formLogin().loginProcessingUrl("/app/authentication")
        .successHandler(ajaxAuthenticationSuccessHandler)
        .failureHandler(ajaxAuthenticationFailureHandler)
        .usernameParameter("j_username")
        .passwordParameter("j_password").permitAll().and().logout()
        .logoutUrl("/app/logout")
        .logoutSuccessHandler(ajaxLogoutSuccessHandler)
        .deleteCookies("JSESSIONID").permitAll().and().csrf().disable()
        .headers().frameOptions().disable().authorizeRequests()
        .antMatchers("/app/rest/register").permitAll()
        .antMatchers("/app/rest/activate").permitAll()
        .antMatchers("/app/rest/authenticate").permitAll()
        .antMatchers("/app/rest/logs/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/app/**").authenticated()
        .antMatchers("/metrics/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/health/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/trace/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/dump/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/shutdown/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/beans/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/info/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/autoconfig/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/env/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/trace/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/api-docs/**")
        .hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/protected/**").authenticated();

    }

    @EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
    private static class GlobalSecurityConfiguration extends
        GlobalMethodSecurityConfiguration {
    }
}
Теги:
spring-mvc
authentication
ldap
jhipster

5 ответов

2
Лучший ответ

Механизм аутентификации по умолчанию использует реализацию "UserDetailsService", его следует называть "com.comcast.castit.security.UserDetailsService" в вашем проекте.

Этот код имеет простое "loadUserByUsername", которое выбирает пользователя в соответствии с его логином и получает его полномочия.

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

Существует руководство по использованию LDAP с Spring Security/Spring Boot, вы можете проверить его здесь: https://spring.io/guides/gs/authenticating-ldap/

Конечно, было бы лучше, если бы у нас была специальная документация для JHipster, поэтому, если вам удастся и у вас будет время, ваши отзывы будут наиболее приветствуемыми!

2

В SecurityConfiguration.java измените функцию configureGlobal на:

@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    /*auth
        .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());*/

    auth.ldapAuthentication()
    .userSearchBase("ou=Users")
    .userSearchFilter("(uid={0})")
    .groupSearchBase("ou=Groups")
    .groupSearchFilter("member={0}")
    .contextSource()
    .url("ldap://127.0.0.1:10389/o=myorganisation");
}

Я прокомментировал предыдущий код. Затем ваше приложение будет проходить проверку подлинности с вашего сервера ldap. Он по-прежнему будет проверять базу данных для сведений о пользователе, и если пользователь не существует в таблице пользователей, у вас будут проблемы вроде: userRepository.findOneByLogin(login) который ищет пользователя в базе данных с использованием существующего имени пользователя.

Но аутентификация произойдет с вашими учетными данными ldap.

1

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

Следующий класс используется для получения контекста вашего LDAP-сервера и пользовательских атрибутов.

public class LDAPHelper {

private static LDAPHelper instance = null;

protected LDAPHelper() {
    // Exists only to defeat instantiation
}

public static LDAPHelper getInstance() {
    if (instance == null) {
        instance = new LDAPHelper();
    }
    return instance;
}

public boolean validateLogin(String username, String password) {
    return (getLdapContext(username, password) != null);
}

private LdapContext getLdapContext(String username, String password) {
    Hashtable<String, String> env = new Hashtable<String, String>();

    env.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.ldap.LdapCtxFactory");
    env.put("com.sun.jndi.ldap.read.timeout", "120000");
    env.put(Context.SECURITY_AUTHENTICATION, "Simple");
    env.put(Context.SECURITY_PRINCIPAL, "VF-ROOT\\" + username);
    env.put(Context.SECURITY_CREDENTIALS, password);
    env.put(Context.PROVIDER_URL, "*ldap url*");
    System.out.println(username);
    try {
        return new InitialLdapContext(env, null);
    } catch (NamingException e) {
        return null;
    }
}

public User getUserAttributes(String username, String password)
        throws NamingException { ... }

В AccountResource я изменил метод register для поиска пользователя на LDAP-сервере, и, если пользователь существует, я добавляю его в локальную базу данных, если он еще не добавлен. Вы вызываете этот метод перед входом в систему, чтобы убедиться, что только пользователи, которые находятся на LDAP-сервере, могут войти в ваше приложение.

     @RequestMapping(value = "/register", method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE,
        MediaType.TEXT_PLAIN_VALUE })
@Timed
public ResponseEntity<?> registerAccount(@Valid @RequestBody ManagedUserDTO managedUserDTO,
        HttpServletRequest request) {

    HttpHeaders textPlainHeaders = new HttpHeaders();
    textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);

    // user exists in LDAP server
    if (LDAPHelper.getInstance().validateLogin(managedUserDTO.getLogin(), managedUserDTO.getPassword())) {

        // user was already created in the local database
        if (userRepository.findOneByLogin(managedUserDTO.getLogin().toLowerCase()).isPresent()) {

            return new ResponseEntity<>("user exists in database", textPlainHeaders, HttpStatus.OK);

        } else {

            try {
                User userAux = LDAPHelper.getInstance().getUserAttributes(managedUserDTO.getLogin(), managedUserDTO.getPassword());                             

                User user = userService.createUserInformation(managedUserDTO.getLogin(), managedUserDTO.getPassword(), userAux.getFirstName(),
                        userAux.getLastName(), userAux.getEmail(), managedUserDTO.getLangKey());                                        

                } catch (NamingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                return new ResponseEntity<>("user created in database", textPlainHeaders, HttpStatus.OK);
            }
        } else {
            return new ResponseEntity<>("user does not exist in ldap", textPlainHeaders, HttpStatus.UNAUTHORIZED);
        }
}
1

Если вам нужен UserDetailsContextMapper (для властей), добавьте следующее:

provider.setUserDetailsContextMapper(new UserDetailsContextMapper() {

        @Override
        public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
            // TODO Auto-generated method stub

        }

        @Override
        public UserDetails mapUserFromContext(DirContextOperations ctx,
                String username,
                Collection<? extends GrantedAuthority> authorities) {

            User anwender = userRepository.findOneByAnwender(username);

            Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(
                    "ROLE_ADMIN");
            grantedAuthorities.add(grantedAuthority);

            return new org.springframework.security.core.userdetails.User(
                    username, "1", grantedAuthorities);
        }
    });
0

Удалите следующий фрагмент кода из SecurityConfig.java

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return (AuthenticationManager) ldapAuthenticationManager;
}

Затем создайте класс LDAPAuthenticationManager

package com.digitronic.isda.security;

import org.springframework.ldap.core.AuthenticationSource;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.stereotype.Component;

@Component("authenticationManagerBean")
public class LDAPAuthenticationManager implements AuthenticationManager {


    LdapAuthenticationProvider provider = null;

    @Override
    public Authentication authenticate(Authentication arg0)
            throws AuthenticationException {

        return provider.authenticate(arg0);
    }

    LDAPAuthenticationManager() {

        DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
                "ldap://127.0.0.1:389");
        contextSource.setUserDn("test.com\\Administrator");
        contextSource.setCacheEnvironmentProperties(true);
        try {
            contextSource.afterPropertiesSet();
        } catch (Exception e) {

            e.printStackTrace();
        }
        contextSource.setPassword("asdasdasdjBj,K");

        LdapContextSource ldapSrc = new LdapContextSource();
        ldapSrc.setUrl("ldap://127.0.0.1:389");
        ldapSrc.setUserDn("test.com\\Administrator");
        ldapSrc.setPassword("asdasdasdjBj,K");
        ldapSrc.setAnonymousReadOnly(false);
        ldapSrc.setCacheEnvironmentProperties(true);

        try {
            ldapSrc.afterPropertiesSet();
        } catch (Exception e) {
            e.printStackTrace();
        }

        ldapSrc.setAuthenticationSource(new AuthenticationSource() {

            @Override
            public String getPrincipal() {
                // TODO Auto-generated method stub
                return "test.com\\Administrator";
            }

            @Override
            public String getCredentials() {
                // TODO Auto-generated method stub
                return "asdasdasdjBj,K";
            }
        });

        FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch(
                "cn=Users,dc=digitronic,dc=lan", "(sAMAccountName={0})",
                ldapSrc);

        BindAuthenticator bindAuth = new BindAuthenticator(contextSource);
        bindAuth.setUserSearch(userSearch);
        provider = new LdapAuthenticationProvider(bindAuth);
    }
}
  • 0
    @Component ("authenticationManagerBean") также потребуется, поскольку это не упоминается в коде jhibster.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню