Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security null pointer exception

I'm trying to map the users in my database to the Spring Security users, but without much luck. My UserServiceImpl is as follows (the autowiring normally works fine when I'm calling it through a servlet, but throws a null pointer when used in Spring Security...

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService, UserDetailsService {

    protected static Logger logger = Logger.getLogger("service");

    @Autowired
    private UserDAO userDao;

    public UserServiceImpl() {
    }

    @Transactional
    public User getById(Long id) {
        return userDao.getById(id);
    }

    @Transactional
    public User getByUsername(String username) {
        return userDao.getByUsername(username);
    }

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        UserDetails user = null;
        try {
            System.out.println(username);
            User dbUser = getByUsername(username);

            user = new org.springframework.security.core.userdetails.User(
                    dbUser.getUsername(), dbUser.getPassword(), true, true,
                    true, true, getAuthorities(dbUser.getAccess()));
        } catch (Exception e) {
            e.printStackTrace();
            logger.log(Level.FINE, "Error in retrieving user");
            throw new UsernameNotFoundException("Error in retrieving user");
        }

        // Return user to Spring for processing.
        // Take note we're not the one evaluating whether this user is
        // authenticated or valid
        // We just merely retrieve a user that matches the specified username
        return user;
    }

    public Collection<GrantedAuthority> getAuthorities(Integer access) {
        // Create a list of grants for this user
        List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);

        // All users are granted with ROLE_USER access
        // Therefore this user gets a ROLE_USER by default
        logger.log(Level.INFO, "User role selected");
        authList.add(new GrantedAuthorityImpl("ROLE_USER"));

        // Check if this user has admin access
        // We interpret Integer(1) as an admin user
        if (access.compareTo(1) == 0) {
            // User has admin access
            logger.log(Level.INFO, "Admin role selected");
            authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
        }

        // Return list of granted authorities
        return authList;
    }
}

I get the following exception (the first line is the System.out)

dusername
java.lang.NullPointerException
    at org.assessme.com.service.UserServiceImpl.getByUsername(UserServiceImpl.java:40)
    at org.assessme.com.service.UserServiceImpl.loadUserByUsername(UserServiceImpl.java:50)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:81)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:194)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:722)

So it looks like my userDao is not autowiring correctly, but it works fine when I call the service layer from a servlet, just apparently not when using Spring-Security.

Line 40 refers to return userDao.getByUsername(username);

Does anyone have any ideas how I can get the userDao to be populated through @autowired? As I say, it works fine when I call it through a servlet, just not when trying to use spring-security.

Is there any easier way I can map users and passwords in Spring-security?

My security-app-context is as follows...

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" 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/security 
                    http://www.springframework.org/schema/security/spring-security-3.1.xsd"
                    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx">
<context:annotation-config />
<context:component-scan base-package="org.assessme.com." />


    <http pattern="/static/**" security="none" />
    <http use-expressions="true">
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/*" access="isAuthenticated()" />
        <!-- <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')" 
            /> -->
        <!-- <intercept-url pattern="/listAccounts.html" access="isAuthenticated()" 
            /> -->
        <!-- <intercept-url pattern="/post.html" access="hasAnyRole('supervisor','teller')" 
            /> -->
<!--        <intercept-url pattern="/*" access="denyAll" /> -->
        <form-login />
        <logout invalidate-session="true" logout-success-url="/"
            logout-url="/logout" />
    </http>

    <authentication-manager>
        <authentication-provider user-service-ref="UserDetailsService">
          <password-encoder ref="passwordEncoder"/>
        </authentication-provider>
</authentication-manager>
<context:component-scan base-package="org.assessme.com" /><context:annotation-config />
<beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService" autowire="byType"/>


</beans:beans> 

I guess my question is, why is my userDao @Autowired not working with spring-security, yet it works fine when used in a servlet to return the user object? For example, the following servlet works fine...

Why is my autowiring (as it throws a NPE) not working when it's going through spring-security, yet it works fine when being called from a servlet?

EDIT :- added

But now I get

ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 9 in XML document from ServletContext resource [/WEB-INF/spring/security-app-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 30; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'context:annotation-config'.
like image 202
david99world Avatar asked Jul 07 '12 12:07

david99world


1 Answers

You care creating your service through bean declaration:

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService"/>

therefore you need to configure it as eligible for autowiring by setting property autowire. Default is No. The configuration will look like:

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService"  autowire="byType" />

additionally you could indicate that this bean will participate in others bean autowire process by configuring property autowire-candidate="true".

Check documentation in order to find out which is the best strategy for your bean have its properties autowired. I personally use byType and constructor, but it depends really on your requirement.

Another solution would be configure default-autowire="true" in the tag beans of your context.

like image 168
Francisco Spaeth Avatar answered Nov 03 '22 01:11

Francisco Spaeth