0

I'm facing a serious problem and I can't figure out how to solve it.

Basically, in my Custom Authentication provider, I can't autowire my customUserDetailsService, it is returning a null pointer exception.

I'm gonna paste all the classes I'm using plus the exception, the problem here is that it autowires but it returns NULL, it doesn't give me an error on the autowiring itself.

SecurityConfig class:

package esercizio.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // SecurityContextHolder.getContext().getAuthentication();
        auth.authenticationProvider(new DbAuthenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // .addFilterBefore(
                // new HeaderUsernamePasswordAuthenticationFilter(authenticationManager()),
                // BasicAuthenticationFilter.class)
                .csrf().disable().authorizeRequests().antMatchers("/resources/**").permitAll().antMatchers("/auth/**")
                .hasRole("USER").anyRequest().authenticated().and().formLogin()
                // .loginPage("/login.jsp")
                .loginProcessingUrl("/signin").permitAll().failureForwardUrl("/errorPage")
                .successForwardUrl("/successPage").and().logout().addLogoutHandler(customLogoutHandler())
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
        // .and()
        // .exceptionHandling().accessDeniedPage("/403");
    }

    @Bean
    public CustomLogoutHandler customLogoutHandler() {
        return new CustomLogoutHandler();
    }
}

Custom Authentication Provider:

package esercizio.security;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

@Component
public class DbAuthenticationProvider implements AuthenticationProvider {
    Logger logger = LogManager.getLogger(this.getClass());

    @Autowired
    UserDetailsService customUserDetailsService;

    public DbAuthenticationProvider() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String name = authentication.getName();
        Object credentials = authentication.getCredentials();
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        UserDetails user = customUserDetailsService.loadUserByUsername(name);
        Authentication auth = null;

        if (!(credentials instanceof String)) {
            return null;
        }
        String password = null;
        try {
            password = getMD5(credentials.toString());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (user != null && (user.getUsername().equals(name) && user.getPassword().equals(password))) {
            grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuthorities);
        } else {
            throw new BadCredentialsException("Errore nell'autenticazione");
        }

        return auth;
    }

    @Override
    public boolean supports(Class<?> arg0) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(arg0));
    }

    public String getMD5(String data) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");

        messageDigest.update(data.getBytes());
        byte[] digest = messageDigest.digest();
        StringBuffer sb = new StringBuffer();
        for (byte b : digest) {
            sb.append(Integer.toHexString((int) (b & 0xff)));
        }
        return sb.toString();
    }

}

CustomUserDetailsService

package esercizio.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import esercizio.database.dao.UsersDAO;
import esercizio.database.dto.UsersDTO;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UsersDAO usersDAO;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        UsersDTO userTemp = usersDAO.findByUsername(username);

        return userTemp;
    }
}

WEB.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <servlet>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>esercizio.InitServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/springmvc-servlet.xml
            /WEB-INF/spring-security-context.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>InitServlet</servlet-name>
        <url-pattern>/InitServlet</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>esercizio.listener.SessionListener</listener-class>
    </listener>

     <!-- <filter>
        <filter-name>RedirectFilter</filter-name>
        <filter-class>esercizio.filters.RedirectFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>RedirectFilter</filter-name>
        <url-pattern></url-pattern>
    </filter-mapping>  

    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list> --> 

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

</web-app>

Spring-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
    http://www.springframework.org/schema/data/mongo
        http://www.springframework.org/schema/data/mongo/spring-mongo-1.2.xsd
        http://www.springframework.org/schema/data/repository
        http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd">

    <context:component-scan base-package="esercizio" />
    <context:annotation-config />
    <jpa:repositories base-package="esercizio.database.dao" />


    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- max upload size in bytes -->
        <property name="maxUploadSize" value="20971520" /> <!-- 20MB -->

        <!-- max size of file in memory (in bytes) -->
        <property name="maxInMemorySize" value="1048576" /> <!-- 1MB -->

    </bean>

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations"
            value="classpath:/esercizio/properties/db.properties" />
    </bean>

     <bean id="JDBCDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">

        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean> 

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="JDBCDataSource" />
    </bean>


    <!-- <bean id="tjtJTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="JDBCDataSource" />
    </bean> 

    <tx:annotation-driven transaction-manager="tjtJTransactionManager" />-->



    <mvc:resources mapping="/resources/**" location="/resources/theme1/"
        cache-period="31556926" />

    <mvc:annotation-driven />
</beans>

Spring Security xml (it is basically used just to scan and activate annotation config)

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <global-method-security pre-post-annotations="enabled"/>

    <context:annotation-config />

    <context:component-scan base-package="esercizio" />

 </beans:beans>

And last but not least the exception it's giving me

java.lang.NullPointerException
    esercizio.security.DbAuthenticationProvider.authenticate(DbAuthenticationProvider.java:41)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)

If someone can figure out what the problem is I would be thankful forever, it has been like 3 days and I don't seem to be able to solve it.

Fabian
  • 650
  • 2
  • 9
  • 21
  • 1
    Possible duplicate of [Why is my Spring @Autowired field null?](https://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null) – dur Apr 18 '18 at 10:55
  • Maybe [this answer](https://stackoverflow.com/a/58990597/7772054) will help u! – SHIVA Nov 22 '19 at 08:56

2 Answers2

1

I think

@Autowired UserDetailsService customUserDetailsService;

should be

@Autowired CustomUserDetailsService customUserDetailsService;

-1

The main reason is that in your configure(AuthenticationManagerBuilder) you are building a new instance of the DbAuthenticationProvider while injecting it to the authentication-manager (just in this line: auth.authenticationProvider(new DbAuthenticationProvider());) outside the Spring-framework context so the DbAuthenticationProvider instance injected into the AuthenticationManager has no way to autowire the @Autowired UserDetailsService customUserDetailsService.

As this UserDetailsService field will be null a NullPointerException will be thrown in authenticate() method at this line of code: UserDetails user = customUserDetailsService.loadUserByUsername(name);

You can change the way the classes are loaded in many ways, but probably the easiest is taking this block of code:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // SecurityContextHolder.getContext().getAuthentication();
        auth.authenticationProvider(new DbAuthenticationProvider());
    }

And change it to this:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(dbAuthenticationProvider);
    }        

I think it is the easiest way of changing your code so that it gets to work

jlumietu
  • 6,234
  • 3
  • 22
  • 31