PreAuthorize annotation doesn't work with jersey - java

I'm trying to secure a jersey service using spring security annotations without any luck.
I've added this section to web.xml:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.test.proj.ui.web.rest;com.fasterxml.jackson.jaxrs</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.commons.ui.web.jersey.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Also enabled the pre-post-annotations using this on applicationContext:
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
And this is my service class:
#Component
#Path("/user/{uid: .*}")
public class UserResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
#PreAuthorize("hasRole('ROLE_MANAGE_USER')")
public Response getUserDetail(#PathParam("uid") String uid) {
return "Hi, this is a test";
}
}
Spring security works well in authentication but the authorization doesn't work as expected and ignores the PreAuthorize annotation without any error or log.
I'm using Spring 3.2.4 and Spring Security 3.2.1 and Jersy 2.6.
any idea?
thanks

The spring component scan wasn't configured correctly! To solve the problem, only add component scan correctly and it works.

We were facing exactly the same problem. On the business layer #PreAuthorize annotation worked but on the REST resource didn't. The side effect of this situation was that Spring bean injection didn't work as well. Everything without any error.
The 100% working solution was to use RESTEasy instead of Jersey. They are quite similar so it was not much work.

Related

Spring cloud Zuul with servlet-api 2.5

#EnableZuulProxy doesn't work under a servlet 2.5 container. Is there any workaround to get spring-cloud zuul work under a servet 2.5 container?
Also I could not find the annotation processor of #EnableZuulProxy. Please provide the class which propesses #EnableZuulProxy so that I can better understand what this annotation really does.
Spring Cloud is meant to be run on servlet 3.0. That being said, it is possible to get #EnableZuulProxy running on servlet 2.5. I had to figure out a hack for this as I had to get this working in Tomcat 6.
The main issue is due to the ZuulConfiguration.class, which has the method:
#Bean
#ConditionalOnMissingBean(name = "zuulServlet")
public ServletRegistrationBean zuulServlet() { ... }
The issue here is that ServletRegistrationBean uses javax.servlet.Registration$Dynamic, which is not available until Servlet 3.0. This results in a NoClassDefFoundError.
To work around this, use the spring-boot-legacy project to first register a DispatcherServlet. Secondly, you'll have to manually create a zuul servlet.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
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_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.dm.gateway.microservicegateway.Application</param-value>
</context-param>
<listener>
<listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ContextLifecycleFilter</filter-name>
<filter-class>com.netflix.zuul.context.ContextLifecycleFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ContextLifecycleFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>zuul</servlet-name>
<servlet-class>com.netflix.zuul.http.ZuulServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
I found the best way to remove the auto servlet registration, is to just make a verbatim copy of ZuulConfig called ZuulOverrideConfig, and remove the zuulServlet() method. This is because the ZuulProxyConfiguration extends ZuulConfiguration, and it seemed to create the bean even when i tried to override it. I'm not 100% on the mechanics behind this, so there may be a better way.
The second change I made in ZuulOverrideConfig was to call an extended implementation of ZuulFilterInitializer, called 'LegacyZuulFilterInitializer`. This is because for some reason, the Zuul servlet was being crated, and able to be invoked, but no filters were bootstrapped. This extension is a hacky way to get the filters to bootstrap.
Next, I created a copy of ZuulProxyConfiguration called ZuulLegacyProxyConfiguraiton, and had it extend ZuulOverrideConfig.class.
Finally, I annotated the Application class as follows.
#EnableCircuitBreaker
#EnableDiscoveryClient
#Import(ZuulLegacyProxyConfiguration.class)
#SpringBootApplication
public class Application {....}
After all these hacks, the implementation finally worked as expected. I wouldn't suggest using this for long, as it's pretty hacky. You won't get configuration class updates automatically when moving to new versions, and I can't guarantee that something won't break randomly!
This is using Spring Cloud 1.1.4.RELEASE
Gist of all the code.
#EnableZuulProxy is from Spring Cloud which is based on Spring Boot which is Servlet 3.0 and above. If you need to use Servlet 2.5 you can use the Netflix APIs directly.
#EnableZuulProxy is meta-annotated with #Import(ZuulProxyConfiguration.class) so I guess that's what you mean when you say "propesses"? If you don't know what an #Import is, go and read up on Spring.

how to have spring manage bean lifecycle instead of jersey

I'm using jersey 2.17 on tomcat 8, and I'm having a problem with what I think should be a very straightforward and common use case.
I have various beans defined in a spring XML file. I've now annotated one of them to expose some methods as rest APIs. This is a singleton bean, with a reference to another bean injected in the spring XML configuration.
My rest APIs are working, but the problem is that every time one is invoked a new instance of the bean class is created, and my bean reference is null. My understanding is that this is because jersey is managing the lifecycle instead of spring, and I need SpringComponentProvider, which will then provide the singleton.
I included jersey-spring3-2.17.jar in my application, and I specified the spring package in the servlet configuration in web.xml, as follows:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.rest.package;org.glassfish.jersey.server.spring</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.tracing.type</param-name>
<param-value>ALL</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I know that the jersey.config.server.provider.packages parameter is being picked up because the annotated class in my.rest.package gets found, but the SpringComponentProvider is apparently not being registered, because I'm still getting a new instance of my bean every time.
I tried specifying the class explicitly like this:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.spring.SpringComponentProvider</param-value>
</init-param>
That didn't change the behavior either.
Any insights or debugging suggestions appreciated.
UPDATE: I realized that the version of my spring jars was behind the version expected by my jersey jars, and I think that's the problem. Once I'm able to update spring, if that fixes it I'll close this.
Jersey will create a new instance on each call regardless if you have an XML bean of the same class as singleton in spring context:
https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e2331
Also see this response on how to change that behavior:
https://stackoverflow.com/a/14739010/2879838
Within your Jersey Resource class, since you already added the jersey-spring dependency, you can simply add the #Autowire annotation on your member variable that you say is injected via XML file in spring. This will spring-inject the dependency when Jersey instantiates the resource on each request.
Hope this helps.
When I finally was able to update my spring, it turned out that was not the issue. I had to add #Component as well as #Singleton to my resource in order for jersey to recognize it as a spring-managed singleton. This problem would never have arisen if I was using annotations for spring; it happened because I was using XML to create the spring beans.

Apache CXF - JAX-RS Security

Working towards getting a Kerberos authenticated Web Service up and running and while Apache CXF seems to meet my requirements I'm struggling to get things started.
Hosting on Tomcat 7 and my super simple test service works but I can't figure out how to get CXF to provide security:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
#Path("test")
public class ItemResource {
public ItemResource() {
}
#GET
#Produces("application/json")
public String getJson(#QueryParam("name") int test) {
return "test";
}
}
Web.xml
<servlet>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>net.example.test/param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
The documentation says I can protect the Rest service with the org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter but I'm unsure as to how to do this.
Any help would be appreciated.
If you want to use CXF's KerberosAuthenticationFilter you have to use CXF as JAX-RS implementation, instead of Jersey.
You can find out how to do that on CXF JAX-RS help pages or in this tutorial. First you have to remove all configuration from web.xml because it is valid only for Jersey. Then follow the tutorial to create the service.
Finally you have to add mentioned KerberosAuthenticationFilter to CXF spring configuration like in the cited documentation.
EDIT:
Because linked tutorial indeed does not run I fixed it. You can download it from my github project RestWithCXF.
You might also find useful samples in samples\jax_rs of CXF distro.

Logging JSON request and response for jersey

I have a JAVA web application application, which exposes RESTful apis. My requirement is to log all the JSON requests and responses that are handled by the server.
Is there any parameter like -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true for JAX-WS?
I am also exploring AOP approach. What method signature should I add in the AOP pattern?
I am using Tomcat server and jersey for the JAX-RS implementation.
use LoggingFilter. Just add the following to your web.xml:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
<!-- Enable Jersey tracing support in Glassfish -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter</param-value>
</init-param>
This worked for me (Jersey 2.x)

Spring MVC: RESTful web services + BlazeDS integration possible in the same web application?

I have a Spring MVC web application which provides RESTful web services via a controller class (annotated with #Controller) which has methods mapped to specific request types and signatures via #RequestMapping annotations.
I have attempted to integrate a BlazeDS service destination into the mix by 1) adding the HttpFlexSession listener to the web.xml, 2) adding the flex:message-broker and flex:remoting-destination declarations to my Spring application context configuration file, and 3) adding a generic /WEB-INF/flex/services-config.xml.
The above BlazeDS integration steps appear to have hosed my RESTful web services, in that it appears that requests are no longer being routed to the controller methods.
Is it even possible to do this, i.e, to have a single web application which 1) services HTTP requests via request mapped controller methods and 2) services remote object method calls (i.e. from a Flex client) via a BlazeDS service? If so then can anyone tell me what it may be that I'm doing wrong?
Thanks in advance for your help.
Yes, it's possible, but it requires a little extra configuration.
Essentially you need to create two seperate dispatchers, each with a different path.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<name>flex</name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<name>spring-mvc</name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Now requests to http://yourapp/app/somewhere are routed to Spring MVC, and requests to http://yourapp/messagebroker are routed through BlazeDS.
Also, you'll need to split out your spring context files into three:
A common context (named applicationContext.xml in the above example)
One for Spring MVC (named spring-mvc-servlet.xml in the above example)
One for Flex (named flex-servlet.xml in the above example)
Check out this section from the Spring/BlazeDS docs for more info.

Categories