seysn seysn - 1 year ago 156
Java Question

JHipster Using LDAP Authentification

I've started to use JHipster weeks ago and everything went find since now. I want to have a LDAP authentification with at the same time the default authentification of JHipster.

I followed this https://jhipster.github.io/tips/016_tip_ldap_authentication.html and it doesn't work as planned.
Actually my configuration is connecting well to my LDAP server and i know by viewing logs that the login search into the LDAP server and compare the password.

The problem is the login fail with the error :

UT005023: Exception handling request to /api/authentication

org.springframework.security.core.userdetails.UsernameNotFoundException: User nseys was not found in the database
at com.mycompany.myapp.security.PersistentTokenRememberMeServices.lambda$onLoginSuccess$1(PersistentTokenRememberMeServices.java:116)
at java.util.Optional.orElseThrow(Optional.java:290)
at com.mycompany.myapp.security.PersistentTokenRememberMeServices.onLoginSuccess(PersistentTokenRememberMeServices.java:116)
at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.loginSuccess(AbstractRememberMeServices.java:294)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
...


The thing is I want JHipster to automatically create the user in database when it doesn't exist in there with a mapping of parameters (but only when it's a LDAP user) and just connect if it's already done.

I've searched Spring-security solution aswell but the implementations are too far away from the initial files created by JHipster and I don't want to destroy all this.

Answer Source

Well I tried something that work, I don't know if this is how I should have done, but since I've found nothing about that, and it's not documented alot, I'll stick with that solution unless I find a better solution.

// PersistentTokenRememberMeServices.java

protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication
    successfulAuthentication) {

    String login = successfulAuthentication.getName();

    log.debug("Creating new persistent login for user {}", login);

    PersistentToken t = new PersistentToken();
    t.setSeries(RandomUtil.generateSeriesData());
    t.setTokenValue(RandomUtil.generateTokenData());
    t.setTokenDate(LocalDate.now());
    t.setIpAddress(request.getRemoteAddr());
    t.setUserAgent(request.getHeader("User-Agent"));

    PersistentToken token = userRepository.findOneByLogin(login).map(u -> {
        t.setUser(u);
        return t;
    }).orElse(null);

    if (token == null) {
        if (successfulAuthentication.getPrincipal() instanceof LdapUserDetails) {
            User ldapUser = new User();
            ldapUser.setLogin(login);
            ldapUser.setPassword(RandomStringUtils.random(60)); // We use LDAP password, but the password need to be set
            ldapUser.setActivated(true);

            CustomLdapUserDetails customLdapUserDetails = (CustomLdapUserDetails) successfulAuthentication.getPrincipal();
            ldapUser.setEmail(customLdapUserDetails.getEmail());
            ldapUser.setFirstName(customLdapUserDetails.getFirstName());
            ldapUser.setLastName(customLdapUserDetails.getLastName());

            Set<Authority> authorities = new HashSet<>();
            authorities.add(this.authorityRepository.findOneByName("ROLE_USER"));
            ldapUser.setAuthorities(authorities);
            ldapUser.setLangKey("fr");

            userRepository.save(ldapUser);
            t.setUser(ldapUser);
            token = t;
        } else {
            throw new UsernameNotFoundException("User " + login + " was not found in the database");
        }
    }
    ...
}

And I added a contextMapper to get the attributes in the LDAP server

// SecurityConfiguration.java
@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
    return new LdapUserDetailsMapper() {
        @Override
        public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
            UserDetails details = super.mapUserFromContext(ctx, username, authorities);
            return new CustomLdapUserDetails((LdapUserDetails) details, ctx);
        }
    };
}

@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    LdapContextSource contextSource = new LdapContextSource();
    contextSource.setUrl(applicationProperties.getLdap().getUrl());
    contextSource.setBase(applicationProperties.getLdap().getBase());
    contextSource.setUserDn(applicationProperties.getLdap().getUserDn());
    contextSource.setPassword(applicationProperties.getLdap().getPassword());
    contextSource.afterPropertiesSet(); //needed otherwise you will have a NullPointerException in spring

    auth.ldapAuthentication()
        .userDetailsContextMapper(userDetailsContextMapper())
        .userSearchBase(applicationProperties.getLdap().getSearchBase()) //don't add the base
        .userSearchFilter(applicationProperties.getLdap().getSearchFilter())
        .contextSource(contextSource)
    ;
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download