Ajax request with JAX-RS/RESTEasy implementing CORS - ajax

I have two servers (Apache and JBoss AS7) and I need to provide access to all http methods to a client. All these request must be sent via ajax.
Example of the client code:
$.ajax({
type: "get",
url: "http://localhost:9080/myproject/services/mobile/list",
crossDomain: true,
cache: false,
dataType: "json",
success: function(response) {
console.log(response);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
console.log(jqXHR.responseText);
console.log(errorThrown);
}
});
In JBoss AS7 I'm using RESTEasy, implementing CORS as follows:
#Path("/mobile")
#Provider
#ServerInterceptor
public class GroupMobile implements MessageBodyWriterInterceptor {
#Inject
private GroupDAO groupDAO;
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public List<Group> getGroups() {
return groupDAO.listAll();
}
#Override
public void write(MessageBodyWriterContext context) throws IOException,
WebApplicationException {
context.getHeaders().add("Access-Control-Allow-Origin", "*");
context.proceed();
}
#OPTIONS
#Path("/{path:.*}")
public Response handleCORSRequest(
#HeaderParam("Access-Control-Request-Method") final String requestMethod,
#HeaderParam("Access-Control-Request-Headers") final String requestHeaders) {
final ResponseBuilder retValue = Response.ok();
if (requestHeaders != null)
retValue.header("Access-Control-Allow-Headers", requestHeaders);
if (requestMethod != null)
retValue.header("Access-Control-Allow-Methods", requestMethod);
retValue.header("Access-Control-Allow-Origin", "*");
return retValue.build();
}
}
web.xml and beans.xml are empty files.
When I access MyIP:8080 (Apache), I get the error message:
XMLHttpRequest cannot load http://localhost:9080/myproject/services/mobile/list?_=1359480354190. Origin http://MyIP:8080 is not allowed by Access-Control-Allow-Origin.
Does anybody know what is wrong?

The newest resteasy (3.0.9-Final) include a utility class org.jboss.resteasy.plugins.interceptors.CorsFilter.
You can add the CorsFilter object into Application's singleton
objects set, or add it into ProviderFactory in ResteasyDeployment
directly.
The following is the sample application class:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;
#ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
Set<Object> singletons;
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> clazzes = new HashSet<>();
clazzes.add(VersionService.class);
return clazzes;
}
#Override
public Set<Object> getSingletons() {
if (singletons == null) {
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().add("*");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
return singletons;
}
}

The problem you are having is your are trying to do cross-site scripting. You accessed the page at http://MyIP:8080 and so the browser is preventing you from accessing resources outside that domain. This is very browser specific and browser based work arounds will all be different (you can disable security in Chrome globally, and on a per site basis in IE).
If you load the page as http://localhost:8080, it should then allow you access the query. Alternatively, you can implement a proxy which will forward the request.

Sounds like the issue is related to https://issues.jboss.org/browse/RESTEASY-878. You may not be able to catch CORS preflight requests with MessageBodyWriterInterceptor. Try using servlet filters (#WebFilter) instead.

Well, I have implemented a small solution, first I do a interceptor in my project Web
I created a class called "CORSInterceptor" the class is of the way.
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.MessageBodyWriterContext;
import org.jboss.resteasy.spi.interception.MessageBodyWriterInterceptor;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
#Provider
#ServerInterceptor
public class CorsInterceptor implements PreProcessInterceptor, MessageBodyWriterInterceptor {
/**
* The Origin header set by the browser at each request.
*/
private static final String ORIGIN = "Origin";
/**
* The Access-Control-Allow-Origin header indicates which origin a resource it is specified for can be
* shared with. ABNF: Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" source origin string | "*"
*/
private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
//
private static final ThreadLocal<String> REQUEST_ORIGIN = new ThreadLocal<String>();
//
private final Set<String> allowedOrigins;
public CorsInterceptor(){
this.allowedOrigins = new HashSet<String>();
this.allowedOrigins.add("*");
}
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException {
if (!allowedOrigins.isEmpty()) {
REQUEST_ORIGIN.set(request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN));
}
return null;
}
#Override
public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException {
if (!allowedOrigins.isEmpty() && (allowedOrigins.contains(REQUEST_ORIGIN.get()) || allowedOrigins.contains("*"))) {
context.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN, REQUEST_ORIGIN.get());
}
context.proceed();
}
}
In the File Web.xml, I add it
<context-param>
<param-name>resteasy.providers</param-name>
<param-value><package>.CorsInterceptor</param-value>
</context-param>
package: Ubication of the class.
Request JQuery that I have used.
$.ajax({
type: 'GET',
dataType: "json",
crossDomain : true,
cache:false,
url: "http://localhost:12005/ProyectoWebServices/ws/servicioTest",
success: function (responseData, textStatus, jqXHR) {
alert("Successfull: "+responseData);
},
error: function (responseData, textStatus, errorThrown) {
alert("Failed: "+responseData);
}
});
it worked fine for me. I hope that it can help you.

I faced the same issue recently and adding my solution which worked for me:
Following is what I did :
I created a class extending javax.ws.rs.core.Application and added a Cors Filter to it.
To the CORS filter, I added corsFilter.getAllowedOrigins().add("http://localhost:4200");.
Basically, you should add the URL which you want to allow Cross-Origin Resource Sharing. Ans you can also use "*" instead of any specific URL to allow any URL.
public class RestApplication
extends Application
{
private Set<Object> singletons = new HashSet<Object>();
public MessageApplication()
{
singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
CorsFilter corsFilter = new CorsFilter();
// To allow all origins for CORS add following, otherwise add only specific urls.
// corsFilter.getAllowedOrigins().add("*");
System.out.println("To only allow restrcited urls ");
corsFilter.getAllowedOrigins().add("http://localhost:4200");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
}
And here is my web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Restful Web Application</display-name>
<!-- Auto scan rest service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
There are some custom changes which you might not require or change like :
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
OR
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
OR
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
The most important code which I was missing when I was getting this issue was, I was not adding my class extending javax.ws.rs.Application i.e RestApplication to the init-param of <servlet-name>resteasy-servlet</servlet-name>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
And therefore my Filter was not able to execute and thus the application was not allowing CORS from the URL specified.
PS: I am using RestEasy version: 3.12.1.Final

Related

How to allow GET method for endpoint programmatically?

I am loading a .war file and add it as web app to the embedded Tomcat server.
#Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
LOGGER.info("Adding web app");
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
String appHome = System.getProperty(Environment.APP_HOME);
String targetFileName = "web-0.0.1-SNAPSHOT.war";
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(targetFileName);
LOGGER.info(System.getProperty("user.name"));
LOGGER.debug("Loading WAR from " + appHome);
File target = new File(Paths.get(appHome, targetFileName).toString());
try {
LOGGER.info(String.format("Copy %s to %s", targetFileName, target.getAbsoluteFile().toPath()));
java.nio.file.Files.copy(resourceAsStream, target.getAbsoluteFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
Context context = tomcat.addWebapp("/", target.getAbsolutePath());
context.setParentClassLoader(getClass().getClassLoader());
} catch (ServletException ex) {
throw new IllegalStateException("Failed to add webapp.", ex);
} catch (Exception e) {
throw new IllegalStateException("Unknown error while trying to load webapp.", e);
}
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
This is working so far but if I access http://localhost:8080/web I am getting
2017-03-04 11:18:59.588 WARN 29234 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound : Request method 'GET' not supported
and the response
Allow: POST
Content-Length: 0
Date: Sat, 04 Mar 2017 10:26:16 GMT
I am sure all I have to do is to allow the GET method on /web and hopefully the static web content provided from the loaded war file will be accessible via web browser.
How/where can I configure the endpoint such that it allows GET requests?
I tried to introduce a WebController as described in this tutorial.
#Controller
public class WebController {
private final static Logger LOGGER = Logger.getLogger(WebController.class);
#RequestMapping(value = "/web", method = RequestMethod.GET)
public String index() {
LOGGER.info("INDEX !");
return "index";
}
}
In the log output I can see that this is getting mapped correctly:
RequestMappingHandlerMapping : Mapped "{[/web],methods=[GET]}" onto public java.lang.String org.ema.server.spring.controller.dl4j.WebController.index()
but it does not change the fact that I cannot visit the website.
I've also configured a InternalResourceViewResolver:
#Configuration
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
private final static Logger LOGGER = Logger.getLogger(MvcConfiguration.class);
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
LOGGER.info("configureViewResolvers()");
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setSuffix(".html");
registry.viewResolver(resolver);
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
web.xml
Since I configure everything in pure Java, this file does not define a lot:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Easy Model Access Server</display-name>
<listener>
<listener-class>org.ema.server.ServerEntryPoint</listener-class>
</listener>
<context-param>
<param-name>log4j-config-location</param-name>
<param-value>WEB-INF/classes/log4j.properties</param-value>
</context-param>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/web/*.html</url-pattern>
</servlet-mapping>
</web-app>
Reproduce
If you want to reproduce this you can simply checkout the entire code from github. All you need to do this:
mkdir ~/.ema
git clone https://github.com/silentsnooc/easy-model-access
cd easy-model-access/ema-server
mvn clean install
java -jar server/target/server-*.jar
This will clone, build and run the server.
The directory ~/.ema directory is required at the moment. It is where the WAR is being copied as the server starts.
My guess is that your web.xml maps any path to the Spring DispatcherServlet, something like:
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Because of <url-pattern>/</url-pattern> any request must be handled by a Spring controller, for this reason your static files are not served by Tomcat. Also a pattern like /*.html would have same effect.
If you have only a few pages you might add one or more mapping to the predefined default servlet for them, before the mapping of Spring (and also before Spring Security if you use it):
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>index.html</url-pattern>
</servlet-mapping>
You may also use <url-pattern>*.html</url-pattern> or, if your resources are under the web path and there are only static resources there: <url-pattern>/web/*</url-pattern>
Maybe all this is done instead in Java code in the org.ema.server.ServerEntryPoint that you have as a listener in web.xml
I think the mapping I wrote up in web.xml is done in your case in method getServletMappings of class org.ema.server.spring.config.AppInitializer, I changed it to use a more strict pattern /rest-api/* instead than /, not sure pattern is correct and everything else works, but now http://127.0.0.1:8080/index.html works
#Override
protected String[] getServletMappings() {
return new String[] { "/rest-api/*" };
}
as I see the url: http://localhost:8080/web is wrong.
You can try: http://localhost:8080/[name-of-war-file]/web

Spring Data Rest: ResourceProcessor configuration is not working properly

I have a strange behaviour with a Spring Data Rest implementation (version 2.5.2.RELEASE).
I'm trying to register a #Bean of ResourceProcessor<Resource<Entity>>, but there is something strange.
I'm trying with two kinds of solutions:
1) Declaring the #Bean in a class:
#Bean
public ResourceProcessor<Resource<Author>> authorProcessor() {
return new ResourceProcessor<Resource<Author>>() {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of bean ResourceProcessor of class RepositoryBaseConfiguration");
return resource;
}
};
}
2) Implementing the interface ResourceProcessor:
#Component
public class AuthorResourceProcessor implements ResourceProcessor<Resource<Author>> {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of class AuthorResourceProcessor");
return resource;
}
}
The processors are completely ignored: the message is never printed.
I noticed that the class org.springframework.data.rest.webmvc.ResourceProcessorInvoker has a constructor:
public ResourceProcessorInvoker(Collection<ResourceProcessor<?>> processors) {
//...
}
This constructor is invoked 2 times at the start of the application instead of only one time (as I will expect), and I don't understand why.
The first time, the "processors" variable is solved with the two beans (as expected) and with the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
But the second time, the "processors" variable is solved with only the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
The second configuration #Override the first one.
Any idea?
The problem depends on the configurations loaded at the startup of the application.
I had this configuration on the web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-web-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.data.rest.webmvc.RepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
So, the ContextLoaderListener loaded the correct configuration in the first time; the "load-on-startup" property of the servlet "RepositoryRestDispatcherServlet" launch a second context configuration load.
I also had a custom class that extended org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration, but this custom class was ignored by the moment that the constructor of RepositoryRestDispatcherServlet load the default RepositoryRestMvcConfiguration, causing the lost of the configurations.
To solve that issue I have created a custom RepositoryRestDispatcherServlet in this way:
public class AppRepositoryRestDispatcherServlet extends DispatcherServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public AppRepositoryRestDispatcherServlet() {
configure();
}
public AppRepositoryRestDispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
configure();
}
private void configure() {
setContextClass(AnnotationConfigWebApplicationContext.class);
setContextConfigLocation(RepositoryBaseConfiguration.class.getName());
}
}
The class is the same as RepositoryRestDispatcherServlet, with the only difference that in the setContextConfigLocation is passed the custom class that extends RepositoryRestMvcConfiguration (RepositoryBaseConfiguration in this example).
Obviously I had to update the web.xml as follows:
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>my.package.AppRepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
In this way, the configuration is correctly loaded and mantained.

RestyGWT- custom url mapping for spring rest service

I have problem that my Spring Rest Controllers is mapped other way than RestyGWT would like.
My application is on: http://localhost:8080/restgwt/
According to web.xml:
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/action-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
My Spring service/controller listen on:
http://localhost:8080/restgwt/service/test
But my RestyGWT service calls this url:
http://localhost:8080/restgwt/restgwt/test
And I don't know how to tell to RestyGWT to change url. Please help.
I know that the simplest solution would be changing in web.xml file servlet url-pattern parameter
from: <url-pattern>/service/*</url-pattern>
to: <url-pattern>/restgwt/*</url-pattern>
but I would like to make RestyGWT to change it's behaviour.
Here paste some additional code:
TestService on GWT side
package pl.korbeldaniel.restgwt.client;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.fusesource.restygwt.client.MethodCallback;
import org.fusesource.restygwt.client.RestService;
public interface TestService extends RestService {
#GET
#Path("test")
public void getInfo(MethodCallback<TestPojo> test);
}
TestService on Spring side
package pl.korbeldaniel.restgwt.server;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController()
public class TestService {
#RequestMapping(value = "test", method = RequestMethod.GET)
public #ResponseBody TestEntity getInfo() {
TestEntity test = new TestEntity();
System.out.println("Hit server for getting _1");
return new TestEntity();
}
}
Reffering to the official documentation:
Configuring service root URLs
There are two ways to configure service root URLs which are appended with the #Path annotation property when building the final service URL. For single service root URL the Defaults.setServiceRoot(String) method can be used. When several services with different service roots are used the #Options annotation is equipped with the serviceRootKey property which can be set to read service root entries provided with the static ServiceRoots.add(String, String) method.
Defaults.setServiceRoot(new Resource( GWT.getModuleBaseURL()).resolve("../rest").getUri());
So my REST path for RestyGWT becomes http://domain-name/myGwtAppModuleName/rest/furtherPath
where furtherPath is javax.ws.rs #Path(..) value
Putting the line directly in GIN ClientModule failed with java.lang.UnsatisfiedLinkError: com.google.gwt.core.client.impl.Impl.getModuleBaseURL()Ljava/lang/String
To avoid error this I've wrapped it up
public class ClientModule extends AbstractPresenterModule {
#Override
protected void configure(){
//your installs and binds here
bind(RestyGwtConfig.class).asEagerSingleton();
}
}
public class RestyGwtConfig {
static {
Defaults
.setServiceRoot(new Resource( GWT.getModuleBaseURL()).resolve("../rest").getUri());
}
}

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>
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?

Adding a Filter and Init Params Progmatically

I need to copy the contents of a web.xml to the WebAppInitializer.class (Java Configuration Class). I have copied the YahooFilter Class from web.xml (see code) but I am not sure how to add the init-params pragmatically.
I have pasted the web.xml and snippet of the Java Configuration class below. Can somebody take a look and provide some feedback?
<web-app>
<display-name>sample</display-Aname>
<filter>
<filter-name>YOSFilter</filter-name>
<filter-class>com.yahoo.yos.YahooFilter</filter-class>
<!--
optional param -
underlying oauth client class
possible values:
net.oauth.client.URLConnectionClient (default)
net.oauth.client.httpclient3.HttpClient3
net.oauth.client.httpclient4.HttpClient4
-->
<init-param>
<param-name>oauthConnectionClass</param-name>
<param-value>net.oauth.client.httpclient4.HttpClient4</param-value>
</init-param>
<!--
optional param -
redirect end-user if an access token is not found, set to false if you
are only making two-legged oauth calls e.g. oauth calls without an
access token to retrieve public information
defauts to true
-->
<init-param>
<param-name>redirect</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!--
The URL where the filter is mapped to will redirect the user to Yahoo for
authorization if an OAuth authorization token has not been obtained for the
user. Should correspond to your callback url
-->
<filter-mapping>
<filter-name>YOSFilter</filter-name>
<url-pattern>/login.jsp</url-pattern>
</filter-mapping>
</web-app>
Java Config Class
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
servletContext.addListener(new HttpSessionEventPublisher());
// servletContext.addListener(new RequestContextListener());
}
#Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
delegatingFilterProxy.setTargetBeanName("springSecurityFilterChain");
// FilterConfig filterConfig = delegatingFilterProxy.getFilterConfig();
YahooFilter yosFilter = new YahooFilter();
return new Filter[] {delegatingFilterProxy,yosFilter};
}
}
Try overriding onStartup() method and programatically register your filter with ServletContext like this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration yahooFilter = servletContext.addFilter("yahooFilter", new YahooFilter());
yahooFilter.setInitParameter("oauthConnectionClass", "net.oauth.client.httpclient4.HttpClient4");
yahooFilter.setInitParameter("redirect", "true");
}

Resources