GWT RPCServlet - Junit + getThreadLocalRequest - java

In my RPCServlet I am using the method AbstractRemoteServiceServlet.getThreadLocalRequest() to get the HttpSession. Now I want to unit-test it. I am using Mockito and thought I just could mock everything, but the method is final and protected.
Is there any other way to Unit-test AbstractRemoteServiceServlet.getThreadLocalRequest().getSession()

At the end you are trying to get a Session. In our case we solve this situation doing this:
Using GUICE for getting our instances (making them available in the GIVEN part of the test)
public class TestServerModule extends com.google.inject.AbstractModule {
#Override
protected void configure() {
.....
bind(HttpServletRequest.class).to(MockRequest.class).in(Singleton.class);
bind(HttpServletResponse.class).to(MockResponse.class).in(Singleton.class);
....
}
....
#Provides
#Singleton
RequestUtil getRequestUtil(final HttpServletRequest req, final HttpServletResponse resp) {
return new RequestUtilsImpl() {
public HttpServletRequest getThreadRequest() {
return req;
}
public HttpServletResponse getThreadResponse() {
return resp;
}
};
}
RequestUitl object contains everything related with Session and more server stuff (that is not important for your problem :D). The important part here is you can have access to the getThreadRequest(), so you have access to getSession() method.
What is the problem? You can not have a real HttpServletRequest object in your instances, so you need to mock them. For doing it, we specified the bind rules at the top.
At the end your test should be something like:
#RunWith(...)
#GuiceModules({TestServerModule.class, ....})
public class YourTest extends junit.framework.TestCase {
#Inject RequestUtil requestUtil;
....
#Test public void
test_session_after_doing_something() {
//GIVEN
HttpSession mockedSession = requestUtil.getThreadRequest().getSession();
....
}
....
}

Related

How to let the resource annotations to be inherited by subclasses

For example, I have a superclass like below
public abstract class SuperServlet extends HttpServlet {
#Resource(name = "varA")
protected static String varA;
}
And the subclass
public class SubServlet extends SuperServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
System.out.println("varA: " + varA);
}
}
I was planned to see the varA's value that I have set in the web.xml, but instead the value I got is null. So I think the resource annotation won't work in a scenario of inheritance like this.
Does anyone know how to make those annotation works on this?
found it. I cannot use it on a static variable because the injection doesn't apply to a field that belong to the class, need to be a individual object.

Access resource method arguments from inside a Jersey filter or interceptor. Or use AOP with resource method

I'm trying to enrich the SLF4J MDC on each request with the user's ID. The problem is that the ID can be passed in many ways, sometimes as a path parameter, sometimes in the body, and sometimes injected by a custom ValueFactoryProvider that first decrypts it.
If I could somehow access all the injected (i.e. already deserialized) parameter values, I could handle all these cases easily.
E.g.
For a resource such as:
#GET
//#Encrypted params are injected by a custom ValueFactoryProvider
public Something getSomething(#Encrypted("userId") String userId) {
return ...;
}
#POST
public Something getSomething(#RequestBody RequestWithUserId requestWithUserId) {
return ...;
}
I could have a filter such as:
public class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Method theMethod = resourceInfo.getResourceMethod();
for (Parameter parameter : theMethod.getParameters()) {
//Deal with the #Encrypted case
if (parameter.isAnnotationPresent(Encrypted.class) && parameter.getAnnotation(Encrypted.class).value().equals("userId")) {
MDC.put("userId", somehowGetTheValue());
}
//Deal with the #RequestBody case
if (parameter.isAnnotationPresent(RequestBody.class) && parameter.getType().equals(RequestWithUserId.class)) {
MDC.put("userId", ((RequestWithUserId)somehowGetTheValue()).getUserId());
}
... //other possibilities
}
}
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
MDC.clear();
}
}
But I don't see a way to implement somehowGetTheValue either from a ContainerRequestFilter an interceptor or anything else...
Jersey uses HK2 under the hood for dependency injection. And HK2 has AOP support. One option for your use case would be use this AOP support. All you need to do is implement a MethodInterceptor and an InterceptionService. In the MethodInterceptor, you can get all the arguments from the MethodInvocation and you can get parameter annotation from the Method
class MyMethodInteceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] args = invocation.getArguments();
// do your logging or whatever with the args.
// invoke method and get return value.
Object returnValue = invocation.proceed();
// if you want to do something with the return
// value before returning it, you can.
return returnValue;
}
}
To use the interceptor, you configure the InterceptionService.
public class MyInterceptionService implements InterceptionService {
private final static MethodInterceptor METHOD_INTERCEPTOR
= new MyMethodInterceptor();
private final static List<MethodInterceptor> METHOD_LIST
= Collections.singletonList(METHOD_INTERCEPTOR);
#Override
public Filter getDescriptorFilter() {
return BuilderHelper.allFilter();
}
#Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
// you implement shouldIntercept
if (shouldIntercept(method)) {
return METHOD_LIST;
}
return null;
}
#Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor) {
return null;
}
}
You determine which method should be intercepted in the getMethodInterceptors() method. If the method should be intercepted, then return a list of interceptors, otherwise return null. A common way of handling this is to create a custom annotation and just annotate the method. The in the above method, just check
if (method.isAnnotationPresent(YourAnno.class)) {
return METHOD_LIST;
}
To make it all work, you just need to register the InteceptionService with HK2. You can do that in an AbstractBinder, which is what is used in a Jersey app to configure your DI.
ResourceConfig config = new ResourceConfig();
config.register(new AbstractBinder() {
#Override
protected void configure() {
bind(MyInterceptionService.class)
.to(InterceptionService.class)
.in(Singleton.class);
}
});
You can see a complete example in this GitHub repo. There is also an official example in the HK2 site. Just see "AOP support" the link at the top of the post.
You can get it like this
StringWriter stringWriter = new StringWriter();
IOUtils.copy(new InputStreamReader(requestContext.getEntityStream()), stringWriter);
System.out.println(stringWriter.toString());// String representation of the payload
requestContext.setEntityInputStream(new ByteArrayInputStream(requestEntity));
Basically the idea is to copy the stream and do any processing and then set the stream back. Because if you don't do that, then in your controller method you would get null, becuase the stream was already read.

SPRING #RestController: Passing Cookie to a Service from Every Method

I have a #RestController in which every method needs to pass a (WebSSO) cookie down to a service. The service in turn uses the cookie for authentication. I am autowiring the service bean in controller. The service has a setter setCredentials(String webSSOCookie). One easy way is to call this setter in every method. I would like to do it better way; for instance using HandlerInterceptor. However the HandlerInterceptor does not have access to the controller (and hence its members) - am I right?
In jersey I could use filter. How do I achieve it in SPRING?
#RestController
#RequestMapping("/documents")
public class ECMRestController {
#Autowired
public ECMService ecmService;
#RequestMapping(value="/{documentId}", method=RequestMethod.DELETE)
public void deleteDocument(#RequestParam("documentId") String documentId) throws IllegalArgumentException, HttpClientErrorException {
// I could get and pass the cookie to ecmService in every method.
// ecmService.setCredentials(webSSOCookieObtainedfromRequest);
// However I don't want to do it that way.
ecmService.deleteDocument(documentId);
}
// Other REST Methods that need to pass the cookie in the same way.
}
You can request the SecurityContextHolder to query the current Authentication that you had customized in a filter.
MyCustomAuth auth = (MyCustomAuth) SecurityContextHolder.getContext().getAuthentication();
auth.getCookie();
or you can just use ThreadLocal in a context that can be retrieve from anywhere:
public class CookieContext {
private static final ThreadLocal<Cookie> COOKIE = new ThreadLocal<>();
private static final CookieContext INSTANCE = new CookieContext();
public void setCookie(Cookie value) {
COOKIE.set(value);
}
public Cookie getCookie() {
return COOKIE.get();
}
public static CookieContext getContext() {
return INSTANCE;
}
}
public class CookieInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
CookieContext context = CookieContext.getContext();
context.setCookie(request.getCookies()[0]);
}
}

How to redirect to external url from service class?

In my current spring project, I am adding several pairs of classes (controller/service) to provide payment option through several payment services. Each one of this classes have a structure like that:
controller
#Controller
#RequestMapping(value = "pagseguro")
public class pagseguroPaymentController extends paymentController<Pagseguro> {
...
#Override
#RequestMapping(value = "comprar", method = RequestMethod.POST)
public void comprar(String payerId, String guid) throws Exception {
this.payment.comprar(payerId, guid);
}
...
}
service
#Service
public class pagseguroPaymentService extends paymentService<Pagseguro> {
...
#Override
public void comprar(String payerId, String guid) throws Exception {
...
String response = checkout.register(null, false);
}
...
}
in the method comprar from service class, I need redirect the application to an URL stored in a String variable (response in the example above).
My initial idea is use the library java.net from Java and create a utilitary class like that:
public class Redirect {
public static String url;
public static void redirect() {
...
}
}
Anyone can give me a hint about how to accomplish that?
To perform a simple redirection, you can inject the HttpServletResponse in your Controller layer:
#RequestMapping(value = "comprar", method = RequestMethod.POST)
public void comprar(String payerId, String guid, HttpServletResponse response) throws Exception {
this.payment.comprar(payerId, guid);
}
And then simply do a redirect using that object:
response.sendRedirect("http://newUrl");
Now - as the Luiggi mentions in the comment - I would not do the redirect itself in the service layer, but rather return a boolean which decides if the redirect needs to be done - and then do it here, in the controller layer.
Hope it helps.

How to mock a SecurityContext

Endpoints with Jersey.
I want to secure an endpoint with a ContainerRequestFilter
#Provider
#Secured
public class AuthorizationRequestFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
final SecurityContext securityContext =
requestContext.getSecurityContext();
//TODO: on logger here...
System.out.printf("Filtering %s request... AuthorizationRequestFilter\n", requestContext.getMethod());
requestContext.getHeaders().add("X-Secured-By", "Jersey >_<");
System.out.printf("SecurityContext: %s (%s).\n", securityContext, securityContext.getAuthenticationScheme());
if (securityContext == null || !securityContext.isUserInRole("privileged")) {
requestContext.abortWith(new UnauthorizedResponse().getResponse());
}
}
}
The annotation #Secured:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
public #interface Secured {}
So I can do this:
#Path("foobar")
public class FooResource {
//...
#Context
SecurityContext securityContext;
//...
#GET
#Secured
#Path(value = "foo")
#Produces(MediaType.APPLICATION_JSON)
public Response getFoo(#Context SecurityContext sc, #Context UriInfo ui, #Context HttpHeaders hh) {
// ...
}
//...
And I'm doing it right (I think), because with my test I don't even pass through the getFoo endpoint but is the ContainerRequestFilter that kicks me out. In fact I receive this (the "X-Secured-By" header is hand-made):
Headers: {X-Secured-By=[Jersey >_< kicked you out!], Content-Length=[97], Date=[Wed, 03 Dec 2014 17:46:50 GMT], Content-Type=[application/json], X-Powered-By=[Jersey ^_^]}
Response: InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:9998/urler/test, status=401, reason=Unauthorized}}
Now it would be nice to mock the SecurityContext.
This is what I'm doing... and if I'm here, it's obviously silly and/or wrong.
public class UrlerResourceTest extends JerseyTest {
//....
#Override
public TestContainerFactory getTestContainerFactory() {
GrizzlyTestContainerFactory grizzlyTestContainerFactory = new GrizzlyTestContainerFactory();
System.out.printf("The GrizzlyTestContainerFactory: %s ", grizzlyTestContainerFactory);
// just for debugging...
return grizzlyTestContainerFactory;
}
#Test
public void testSecuredEndpoint() throws JSONException {
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.isUserInRole(anyString())).thenReturn(true);
Mockito.when(securityContext.getAuthenticationScheme()).thenReturn("Just Mocking...");
ReflectionTestUtils.setField(resource, "securityContext", securityContext, SecurityContext.class);
final Response response = target("foobar")
.path("foo")
.request(MediaType.APPLICATION_JSON)
.get();
System.out.println(getFormattedStringResponseInfo(response));
JSONObject entity = new JSONObject(response.readEntity(String.class));
assertTrue(entity.get("secured").equals(true));
assertTrue(response.getHeaders().containsKey("X-Secured-By"));
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
How can I mock the SecurityContext in my tests?
Thank you so much in advance.
Disclaimer: I'm not really a Mockito user, but from what I understand, mocking is used for situations where you have injected class dependencies (fields), and you mock those dependencies. In which case you still need to set the field with the mocked object. For example
public class TestClass {
TestService testService;
public void doTest() {
System.out.println(testService.getString());
}
public void setTestService(TestService testService) {
this.testService = testService;
}
}
public class TestService {
public String getString() {
return "Hello world";
}
}
#Test
public void toTest() {
TestService testService = Mockito.mock(TestService.class);
Mockito.when(testService.getString()).thenReturn("Hello Squirrel");
TestClass testClass = new TestClass();
testClass.setTestService(testService);
testClass.doTest();
}
You can see we are setting the the TestService in the TestClass with the mocked object. It's not greatest example, as we could simple instantiate TestService, but it shows, from my understanding, how the mocking should work.
That being said, I don't see how it is possible to do this with the AuthorizationRequestFilter, as it's handled by the test container, and we are not instantiating it for a unit test. Even if we were, it would seem intrusive (and redundant) to add a SecurityContext field.
So without a full integration test, where we are starting the server, and using the server's authentication capabilities, it will be difficult to handle the SecurityContext per this use case, as the SecurityContext is created by the container, taking information from the underlying servlet containers authentication mechanism.
One way you can achieve this though (which IMO doesn't seem very elegant - but works), without a full integration test, is to create a a filter which performs before your AuthorizationRequestFilter, and set the SecurityContext from there. Testing aside, this is actually pretty common in cases where we need to implement outr own custom authentication mechanism.
An example of how you might do this for your unit test, might be something like:
public class UrlerResourceTest extends JerseyTest {
...
#Override
public Application configure() {
return new ResourceConfig(FooResource.class)
.register(AuthorizationRequestFilter.class)
.register(AuthenticationFilter.class);
}
#Provider
#Priority(Priorities.AUTHENTICATION)
public static class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestContext.setSecurityContext(new SecurityContext() {
#Override
public Principal getUserPrincipal() {
return new Principal() {
#Override
public String getName() {
return "Stackoverflow";
}
};
}
#Override
public boolean isUserInRole(String string) {
return "privileged".equals(string);
}
#Override
public boolean isSecure() { return true; }
#Override
public String getAuthenticationScheme() { return "BASIC"; }
});
}
}
...
}
This filter will perform before the AuthorizationRequestFilter because of the #Priority annotation. We've set it to Priorities.AUTHENTICATION which will before before any other filter without such annotation. (See Priorities API and Priorities with Jersey. Also the SecurityContext will be passed along between filters and also be injected into your resource class.
As I said, I don't think this is very elegant to have to create another filter, but it works for this purpose. Also I am not too familiar with the Jersey Test Framework, as I'm still beginning with it, but there are many configuration options for deployment within a servlet context. I don't know if we can configure the needed authentication mechanism for this case, but it might be something worth looking into.
Edit: In the beginning I explained about setting the field for the test object, but we can also pass the mocked object to a method. For example we could mock the ContainterRequestContext in the filter method, and call filter ourselves, passing the mocked ContainerRequestContext. But this is only useful when we are actually unit testing the filter class and instantiating it ourselves, which is not the case here.

Categories