Search code examples
springrestspring-securityjava-ee-6spring-security-oauth2

Spring Security with Java EE Restful Service


I have created a Java EE 6 restfull service and tried to integrate that with Spring Security. But, all the time I get different weird exceptions. Which doesn't make any sense or may be make sense but at least not for me.

Direction structure of my application is something like this:

com.security
    UserDetailsSecurityConfig.java
com.service
    ApplicationConfig.java
    UserFacadeREST.java
com.config
    AppConfig.java

My entities are auto generated so no error seems to be there. But, yes the three files seems fishy to me as UserFacadeREST is working fine when I don't integrate my application with Spring Security.

com.UserDetailsSecurityConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService( userDetailsService() );
    }
    @Override
    protected void configure( HttpSecurity http ) throws Exception {
        http
           .httpBasic().and()
           .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and()
           .authorizeRequests().antMatchers("/**").hasRole( "USER" );
    }
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername( final String username ) 
                    throws UsernameNotFoundException {
                if( username.equals( "admin" ) ) {
                    return new User( username, "password", true, true, true, true,
                            Arrays.asList(
                            new SimpleGrantedAuthority("ROLE_USER" ),
                            new SimpleGrantedAuthority( "ROLE_ADMIN" )
                        )
                    );
                } else if ( username.equals( "user" ) ) {
                    return new User( username, "password", true, true, true, true,
                        Arrays.asList(
                            new SimpleGrantedAuthority( "ROLE_USER" )
                        )
                    );
                } 

                return null;
            }
        };
    }

}

com.service.ApplicationConfig.java

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new java.util.HashSet<>();
        addRestResourceClasses(resources);
        return resources;
    }

    /**
     * Do not modify addRestResourceClasses() method.
     * It is automatically populated with
     * all resources defined in the project.
     * If required, comment out calling this method in getClasses().
     */
    private void addRestResourceClasses(Set<Class<?>> resources) {
        resources.add(com.service.UserFacadeREST.class);
    }

}

com.service.UserFacadeREST.java

@Stateless
@Path("user")
public class UserFacadeREST extends AbstractFacade<UpUser> {
    @PersistenceContext(unitName = "PU")
    private EntityManager em;

    public UserFacadeREST() {
        super(User.class);
    }

    @POST
    @Override
    @Consumes({"application/xml", "application/json"})
    public void create(User entity) {
        super.create(entity);
    }
    @GET
    @Path("count")
    @Produces("text/plain")
    public String countREST() {
        return String.valueOf(super.count());
    }

}

com.config.AppConfig.java

@Configuration
@Import( UserDetailsSecurityConfig.class )
public class AppConfig {    
    @Bean 
    public ApplicationConfig applicationConfig() {
        return new ApplicationConfig();
    }
        @Bean 
    public UserFacadeREST userRestService() {
        return new UserFacadeREST();
    }   


}

In whole code I have made few changes for hit and trial. And currently, I am getting an exception.

java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

Before that I was getting another exception which was

WebSecurityConfigurers must be unique. Order of 100 was already used

I am not getting what I am doing wrong in integrating Spring Security with Java EE 6. I am new to Spring so may be I am doing a blunder which seems obvious to me.

My web.xml file is:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="rest-sec" version="3.0">

    <display-name>rest</display-name>

    <!-- Spring security -->
    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>etagFilter</filter-name>
        <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>etagFilter</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>

    <!-- rest -->
    <servlet>
        <servlet-name>rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.labs.entities</param-value> <!-- won't find anything -->
        </init-param>
        <init-param>
            <param-name>dispatchOptionsRequest</param-name>
            <param-value>true</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>rest</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <!-- Disables servlet container welcome file handling. Needed for compatibility 
        with Servlet 3.0 and Tomcat 7.0 -->
    <welcome-file-list>
        <welcome-file />
    </welcome-file-list>

</web-app>

Solution

  • java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

    You need to tell the filter where to look for your context (it's default is to look in a place that is not used by the servlet you created). In your filter add an init param:

        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
        </init-param>
    

    WebSecurityConfigurers must be unique. Order of 100 was already used

    Do you have 2 beans of type WebSecurityConfigurerAdapter? Or is your UserDetailsSecurityConfig being loaded twice?