Spring RestEasy interceptor - spring

I have a Spring boot application with resteasy-spring-3.0.19 and jboss-jaxrs-api_2.0_spec-1.0.0.
I would like to intercept all the rest calls for authorization.
The interceptor is not getting invoked. Also, How can i get the target method #Path annotation value in the interceptor.
Do I need to register this in the Spring boot app?
#Provider
public class AuthorizationtInterceptor implements ContainerRequestFilter{
/**
*
*/
public AuthorizationtInterceptor() {
// TODO Auto-generated constructor stub
}
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String method = requestContext.getMethod();
UriInfo uriInfo = requestContext.getUriInfo();
// Need the target method #Path annotation value ....
}
}
Target Rest class,
#Named
#Singleton
#Path(ROOT_PATH)
public class WebController {
#GET
#Path(TEST_PATH)
#Produces(MediaType.APPLICATION_JSON)
public Response getUser(#Context final HttpServletRequest request) {
}
}

In a post-matching filter (a filter without the #PreMatching annotation), you can use ResourceInfo to get the matched resource class and the resource method.
Inject ResourceInfo in your filter using the #Context annotation:
#Context
private ResourceInfo resourceInfo;
Then get the resource class and extract the #Path annotation:
Path path = resourceInfo.getResourceClass().getAnnotation(Path.class);
To get the resource method, use:
Path path = resourceInfo.getResourceMethod().getAnnotation(Path.class);
Depending on what you are trying to achieve, instead of comparing the value of the #Path annotation for authorization purposes, you could consider binding your filter to a set of resource classes or methods. See more details in this answer.
Depending on how you are setting up your application, you may need to register the filter in your Application subclass or in your web.xml deployment descriptor.

Related

Jersey get Request object programmatically

Is there any way to get the request (HttpServletRequest?) programmatically? I can only find how to do it with an annotation on the endpoint method/class.
Per https://stackoverflow.com/a/5118844/190164 I can add an annotated argument to my endpoint:
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(
#Context HttpServletRequest httpRequest
) {
// The method body
}
Or I can injected in the class(https://stackoverflow.com/a/26181971/190164)
public class MyResource {
#Context
private HttpServletRequest httpRequest;
#GET
public Response foo() {
httpRequest.getContentType(); //or whatever else you want to do with it
}
}
however I would like access to the request in another class that isn't directly linked to Jersey. Adding the #Context injection like in the second example above doesn't work, as the class isn't instantiated by Jersey. I'd like to be able to do something like
HttpServletRequest.getCurrentRequest()
but I haven't been able to find any static method somewhere.
If you are looking for some security solutions you can use servlet filters (create class that implements Filter) or you can implement ContainerRequestFilter and by overriding filter you can perform your filtering .Outside filters The context elements are always only accessible in the controller (where you place the path annotations) , there is no way to access this type of content from outside the controller other than passing it to the method or Object desired:
#Context
private HttpServletRequest httpRequest;
#GET
public Response foo() {
someMethod(httpRequest); //or whatever else you want to do with it
}
}
hope this helps.

Authentication using request scoped context with Spring

I am trying to create custom "userContext" as a SpringBean with request scope but I am unable to do so. Basically I have a Jersey REST api and I want to do authentication and authorization using my custom filters in which I autowire my "userContext" bean. The process looks like this:
REST API called (I expect Spring to create new instance of userContext bean)
AuthenticationFilter autowires new instance of userBean and populates it
AuthorizationFilter autowires the same instance which is populated now and authorize the user
When i first call the REST api (after server restart), it works as expected, but any other call fails, because AutorizationFilter gets an empty instance of userBean. I expect some fundamental misunderstanding of scopes on my part.
Btw: I'd like to avoid using ThreadLocal directly since Request scope should take care of it
I would like to know, why authorizationFilter doesn't see the populated version of the userBean and why the first call works. Thanks in advance for any help.
Just some parts of the code:
#Secured({Role.ADMIN}) //custom annotation
#GET
#Path("{id}")
public Response getUserById(#PathParam("id") Long id) throws IOException, MainException {
#Secured //custom annotation
#Provider
#Priority(Priorities.AUTHENTICATION)
#Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class AuthenticationFilter implements ContainerRequestFilter
#Autowired
private User userContext;
#Secured //custom annotation
#Provider
#Priority(Priorities.AUTHORIZATION)
#Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class AuthorizationFilter implements ContainerRequestFilter {
#Autowired
private User userContext;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class User extends ModelBase implements Serializable {
Since Providers are not request scoped, I had to inject whole ApplicationContext so I could directly modify the right instance of userContext bean (which is request scoped). Basically I did something like this in both filters:
#Autowired
private ApplicationContext applicationContext;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
User userBean=applicationContext.getBean(User.class);
....
userBean.setSomething("aaa");
Then I could just autowire such bean in my REST Resources, because they are request scoped by defaul:
#Component
#Api(value="/users", description = "Endpoint for Users listing")
#Consumes({MediaType.APPLICATION_JSON, Constants.API_VERSIONS.V1_HEADER_XML, Constants.API_VERSIONS.V1_HEADER_JSON})
#Produces({MediaType.APPLICATION_JSON, Constants.API_VERSIONS.V1_HEADER_XML, Constants.API_VERSIONS.V1_HEADER_JSON})
#Path("/users")
public class UserResource {
private static final Logger logger = LoggerFactory.getLogger(UserResource.class);
#Autowired
private User authenticatedUser;
This solution should be viable and resistent against thread race conditions etc.

Spring WS annotated endpoint

I have to replace the deprecated class AbstractMarshallingPayloadEndpoint from springws 2.0. which my class was extending and overriding the invokeInternal method as below.
Example :
public class UpdateUserEndpoint extends AbstractMarshallingPayloadEndpoint {
#Override
protected Object invokeInternal(Object request){
//MY BUSINESS LOGIC here.
}
}
I am trying to replace my class with endpoint annotation.
#PayloadRoot(localPart = "MyRequest", namespace = "MyNamespace")
public MyResponse updateUser(MyRequest request) { ... }
I am ending up with exception while the server startup with a BeanCreationException:
I use Castor marshaller and unmarshaller in mapping.
Need some thoughts to proceed in a right way.

#Endpoint and #Transactional on the same class using Spring-ws library

I am trying to implement a web-service endpoint which would be transactional because I don't want to create a special "worker" class with transactional methods. I'm using Spring-ws library together with Spring framework.
Here is my class definition:
#Endpoint
#Transactional
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyEndpoint implements ApplicationContextAware { ... }
Notice that I explicitly specified proxying method to force using CGLIB.
Also notice that my class implements some interface(s), so by default Spring uses JDK dynamic proxy unless another proxying method is specified. This kind of proxies is not appropriate in my case.
The problem begins on application deployment when PayloadRootAnnotationMethodEndpointMapping class starts working. It collects names of all Spring beans with #Endpoint annotation. My endpoint class is counted twice with names "myEndpoint" and "scopedTarget.myEndpoint". This duplication causes ApplicationContextException with message "Cannot map endpoint [...] on registration key [...]: there's already endpoint [...] mapped".
Question: how can I make my endpoint class being transactional?
You might write your own PayloadRootAnnotationMethodEndpointMapping extension and override the initApplicationContext method. There you can check for the scopedTarget. prefix to filter out unwanted beans:
public class ProxiedBeanAwareEndpointMapping extends PayloadRootAnnotationMethodEndpointMapping {
#Override
protected void initApplicationContext() throws BeansException {
initInterceptors();
String[] beanNames = getApplicationContext().getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!beanName.startsWith("scopedTarget.")) {
Class<?> endpointClass = getApplicationContext().getType(beanName);
if (endpointClass != null && AnnotationUtils.findAnnotation(endpointClass, getEndpointAnnotationType()) != null) {
registerMethods(beanName);
}
}
}
}
}
Or you can use the open session in view approach so you don't need to proxy your #Endpoints.

Check the state validity of a Spring proxied bean without try-catch

I have a bean being created by a service with the following class:
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
System.out.println(request.getRemoteAddr());
return new Access();
}
}
Everything works as expected, except that when the application is starting, this method is being called, probably because I have some other singleton beans that use the Access bean. At the start up there is no request bound to the Thread, and it's expected to get a java.lang.IllegalStateException when trying to access any property of the request parameter.
No problem. The question is, is it possible to check if the underlying HttpServletRequest of the proxy request is null before calling a property that raises the exception?
You probably want to take a look at RequestContextHolder#getRequestAttributes(). That will return null if you're not currently in a context where request scope could be used.
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
if (RequestContextHolder.getRequestAttributes() != null) {
System.out.println(request.getRemoteAddr());
}
return new Access();
}
}
I think the issue here is with separation of concerns. Usually your service layer should not have any dependency on the servlet classes. This is very much a controller/UI concern.
Your service class should be provided with the properties which it needs to do its job. In this case a String. This service method should be called from a controller method which is injected with the servlet request.
Something like the following:
#Controller
public class MyController {
#Autowired
private AccessManager accessManager;
#RequestMapping
public void handleRequest(HttpServletRequest request) {
accessManager.create(request.getRemoteAddr());
}
}
and your service would then look like this:
#Service
public class AccessManager {
public Access create(String remoteAddress) {
return new Access();
}
}
To sum up, anything annotated as #Service shouldn't have access to the Request.

Resources