GWT servlet filter ,How to identify special service request? - gwt

I created a app with GWT+requestfacotry(MVP)+GAE. There are some service or method exposed to GWT client ,such as
1.create
2.remove
3.query
I want to add authorization function to "create" and "remove" ,but not to "query".
I did it with servlet filter :
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
UserService userService = UserServiceFactory.getUserService();
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (!userService.isUserLoggedIn()) {
response.setHeader("login", userService.createLoginURL(request.getHeader("pageurl")));
// response.setHeader("login", userService.createLoginURL(request.getRequestURI()));
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
filterChain.doFilter(request, response);
}
My question is how to identify what request (I mean the request will route to which class and service )coming in ? There are some head fields contain the module name ,but I don't it is the security way to do.
Is it possible to get RequestFacotry relevant class from http request ?
Thanks

It's hard to do this within the servlet-filter. Instead you can provide a custom decorator within the RF ServiceLayerDecorator chain. Implementation can looks like this:
import com.google.web.bindery.requestfactory.server.ServiceLayerDecorator;
public class SecurityDecorator extends ServiceLayerDecorator {
#Override
public Object invoke( Method domainMethod, Object... args ) {
if ( !isAllowed( domainMethod) ) {
handleSecurityViolation();
}
return super.invoke( domainMethod, args );
}
}
To register the additional decorator, provide a custom RF servlet:
import com.google.web.bindery.requestfactory.server.RequestFactoryServlet;
public class SecurityAwareRequestFactoryServlet extends RequestFactoryServlet {
public SecurityAwareRequestFactoryServlet() {
super( new DefaultExceptionHandler(), new SecurityDecorator() );
}
}
and register it in your web.xml:
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.company.SecurityAwareRequestFactoryServlet</servlet-class>
</servlet>

Related

Micronaut: Test POST request

In my Micronaut app I have a simple REST controller:
public class Response {
private String code;
public Response(String code) {
this.code = code;
}
}
#Controller("/api/test")
public class TestController {
#Post("/")
public Response index() {
return new Response("OK");
}
}
How can I tests this edpoint? I tried using
#MicronautTest
public class TestControllerTest {
#Inject
EmbeddedServer server;
#Inject
#Client("/")
HttpClient client;
#Test
void testResponse() {
String response = client.toBlocking()
.retrieve(HttpRequest.POST("/api/test/")); // FIXME `HttpRequest.POST` requires body
assertEquals("{\"code\": \"OK\"}", response);
}
but HttpRequest.POST requires an additional body argument to be specified. In my case there is no body to be sent. (In the real code it is a request to initialize a new object and thus it has to be POST).
Usually, when you implement a POST action, you expect that there is a body sent with the request. In your example, you don't accept any POST body, but you still need to pass anything in the unit test.
You can instantiate the HttpRequest object in the following way:
HttpRequest.POST("/api/test/", "");
You can't pass null, it has to be some non-null value (like an empty string.)

Resty-GWT custom callback on async start and end

I use resty gwt for all server communication. I would like some indicator that would show the operation is in progress.
I consider 2 aproaches:
progressbar, which will show in progress percentage;
animation, that will be showed while operation is in progress, but without any percantage.
I've assumed that I need to add custom filter with callback.
I would like to fire events like: RestyGwtComunicationStart and RestyGwtComunicationEnd, or callback to fire onComunicationStarted and
onComunicationEnded. I would like to have this declared in one place, RestyGWT Dispatcher configuration. Also if there was an error I would like to fetch the error.
But I don't know where to start. There is no word about it in documentations.
Can I ask You for help? How can I do this?
So if you want to know that a request has been sent it is up to you in your GWT app to treat that. You can send an event when you trigger your request. You have multiple way of doing this.
Have a look at Request Dispatcher inside the doc https://resty-gwt.github.io/documentation/restygwt-user-guide.html
Then if you want to get progress info, as HTTP calls are synchronous. So there is no way to do this easily.
The way I have been doing it is the following:
1) Create a first call to initiate a processing on the backend with a POST, this will return the ID of your processing
2) Then do a GET on your processing ID that will return the progress. Once the progress is 100% it will return the ID of the result
3) GET the result with the result ID
(You can mix 2 and 3 together eventually and return result when progress is 100% in the same DTO)
Another option is to replace 2) by pushing info from backend to front end (html5 websocket)
Someone already did it as a pull-request to resty. Guess you can give it a try:
https://github.com/resty-gwt/resty-gwt/pull/151
Unfortunately "Dispatcher/Callback filters" feature does not described in the official documentation. But I can suggest next solution (this code should be placed in EntryPoint implementation of your module):
public void onModuleLoad() {
//...
//used to show busy indicator before send HTTP request
DispatcherFilter busyIndicatorDispatcherFilter = new DispatcherFilter() {
#Override
public boolean filter(Method method, RequestBuilder builder) {
BusyIndicator.show();
return true;
}
};
//used to show busy indicator after HTTP response recieved
CallbackFilter busyIndicatorCallbackFilter = new CallbackFilter() {
#Override
public RequestCallback filter(Method method, Response response, RequestCallback callback) {
BusyIndicator.hide();
return callback;
}
};
//registering FilterawareDispatcher (and busy indicator filters) as default Dispatcher
Defaults.setDispatcher(new DefaultFilterawareDispatcher(
busyIndicatorDispatcherFilter,
new DefaultDispatcherFilter(new DefaultCallbackFactory(busyIndicatorCallbackFilter))));
//...
}
Unfortunately I did not get adequate answer, So I developed my own solution.
At first I've added Resty configuration RestyGwtConfig to my Module configuration
public class ClientModule extends AbstractPresenterModule {
#Override
protected void configure() {
bind(RestyGwtConfig.class).asEagerSingleton();
install(new DefaultModule.Builder()
.defaultPlace(Routing.HOME.url)
.errorPlace(Routing.ERROR.url)
.unauthorizedPlace(Routing.LOGIN.url)
.tokenFormatter(RouteTokenFormatter.class).build());
install(new AppModule());
install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
bind(ResourceLoader.class).asEagerSingleton();
}
}
then I've set Custom distpatcher for all my comunication requests of resty gwt.
import org.fusesource.restygwt.client.Defaults;
import org.fusesource.restygwt.client.Resource;
import pl.korbeldaniel.cms.shared.ServiceRouting;
import com.google.gwt.core.client.GWT;
import com.google.inject.Inject;
public class RestyGwtConfig {
#Inject
public RestyGwtConfig(RestyDispatcher dispatcher) {
Defaults.setDispatcher(dispatcher);
}
}
Then I've added custom filter (ProgressIndicatorFilter) to handle communication's start and end callbacks:
import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.dispatcher.DefaultFilterawareDispatcher;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestException;
import com.google.inject.Inject;
public class RestyDispatcher extends DefaultFilterawareDispatcher {
#Inject
public RestyDispatcher(ProgressIndicatorFilter progressIndicatorFilter) {
addFilter(progressIndicatorFilter);
}
}
in filter class method overriden filter I've added an event trigger (eventBus.fireEvent(new IndicatorEvent("Rest-Gwt Comunication started"));) and registered callback, here is whole code:
import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.dispatcher.DispatcherFilter;
import pl.korbeldaniel.cms.client.template.progressIndicator.IndicatorEvent;
import com.google.gwt.http.client.RequestBuilder;
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;
class ProgressIndicatorFilter implements DispatcherFilter {
private AssistedInjectionFactory factory;
private EventBus eventBus;
#Inject
public ProgressIndicatorFilter(AssistedInjectionFactory factory, EventBus eventBus) {
this.factory = factory;
this.eventBus = eventBus;
}
#Override
public boolean filter(Method method, RequestBuilder builder) {
builder.setCallback(factory.createProgressIndicatorCallback(method));
eventBus.fireEvent(new IndicatorEvent("Resty-Gwt Comunication started"));
return true;
}
}
Registering a callback couldn't be done straight forward, like
new ProgressIndicatorDispatcherCallback()
cause I use dependency injection. So I've created a factory to assist injection as follow:
public interface AssistedInjectionFactory {
ProgressIndicatorDispatcherCallback createProgressIndicatorCallback(Method method);
}
Here and here You can find more Assisted Injection info.
Here is the callback code:
class ProgressIndicatorDispatcherCallback implements RequestCallback {
private RequestCallback requestCallback;
private EventBus eventBus;
#Inject
public ProgressIndicatorDispatcherCallback(#Assisted Method method, EventBus eventBus) {
this.requestCallback = method.builder.getCallback();
this.eventBus = eventBus;
}
#Override
public void onResponseReceived(Request request, Response response) {
endComunicationFireIvent();
requestCallback.onResponseReceived(request, response);
}
#Override
public void onError(Request request, Throwable exception) {
endComunicationFireIvent();
requestCallback.onError(request, exception);
}
private void endComunicationFireIvent() {
eventBus.fireEvent(new IndicatorEvent("Rest-Gwt Comunication ended"));
}
}

How to make the #RestController do not response data as restful? [duplicate]

I have a REST endpoint implemented with Spring MVC #RestController. Sometime, depends on input parameters in my controller I need to send http redirect on client.
Is it possible with Spring MVC #RestController and if so, could you please show an example ?
Add an HttpServletResponse parameter to your Handler Method then call response.sendRedirect("some-url");
Something like:
#RestController
public class FooController {
#RequestMapping("/foo")
void handleFoo(HttpServletResponse response) throws IOException {
response.sendRedirect("some-url");
}
}
To avoid any direct dependency on HttpServletRequest or HttpServletResponse I suggest a "pure Spring" implementation returning a ResponseEntity like this:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
If your method always returns a redirect, use ResponseEntity<Void>, otherwise whatever is returned normally as generic type.
Came across this question and was surprised that no-one mentioned RedirectView. I have just tested it, and you can solve this in a clean 100% spring way with:
#RestController
public class FooController {
#RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect means http code 302, which means Found in springMVC.
Here is an util method, which could be placed in some kind of BaseController:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
But sometimes might want to return http code 301 instead, which means moved permanently.
In that case, here is the util method:
protected ResponseEntity movedPermanently(HttpServletResponse response, String url) { // 301, moved permanently,
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build();
}
As the redirections are usually needed in a not-straightforward path, I think throwing an exception and handling it later is my favourite solution.
Using a ControllerAdvice
#ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {
NotLoggedInException.class
})
protected ResponseEntity<Object> handleNotLoggedIn(
final NotLoggedInException ex, final WebRequest request
) {
final String bodyOfResponse = ex.getMessage();
final HttpHeaders headers = new HttpHeaders();
headers.add("Location", ex.getRedirectUri());
return handleExceptionInternal(
ex, bodyOfResponse,
headers, HttpStatus.FOUND, request
);
}
}
The exception class in my case:
#Getter
public class NotLoggedInException extends RuntimeException {
private static final long serialVersionUID = -4900004519786666447L;
String redirectUri;
public NotLoggedInException(final String message, final String uri) {
super(message);
redirectUri = uri;
}
}
And I trigger it like this:
if (null == remoteUser)
throw new NotLoggedInException("please log in", LOGIN_URL);
if you #RestController returns an String you can use something like this
return "redirect:/other/controller/";
and this kind of redirect is only for GET request, if you want to use other type of request use HttpServletResponse

FrontController with RequestFactory in GWT

I am using RequestFactory with GWT. It all working fine. I have a RequestContext interface that point to my DAO methodes.
Now I want to implement some kind of security check before calling the DAO. The first thing that comes to my mind is to use a FrontController and centralize the security in it, but I don't know to implement it with the RequestFactory. Any thought ?
If you want to test whether the user is authenticated, you can use a servlet filter on the server-side and a custom RequestTransport on the client-side. See the guice-rf-activity archetype at https://github.com/tbroyer/gwt-maven-archetypes for an example.
You can also check on the method-level by using a custom ServiceLayerDecorator and implementing the invoke method, calling report() when the user isn't authorized/authenticated (and handling the onFailure on the client-side). I implemented such a thing, that authorized the user based on #RolesAllowed annotations on the service method or class: https://gist.github.com/tbroyer/6091533
Here's how I implemented the security checking:
On the server side I check to see that every RequestFactory request is associated with a user who has previously logged in. To do this, the web.xml file (in the war/WEB-INF directory) must have a mapping for the servlet class. Here's the entry from the web.xml file:
<servlet>
<servlet-name>requestFactoryServlet</servlet-name>
<servlet-class>org.greatlogic.rfexample2.server.RFERequestFactoryServlet</servlet-class>
<init-param>
<param-name>symbolMapsDirectory</param-name>
<param-value>WEB-INF/classes/symbolMaps/</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>requestFactoryServlet</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
The RFERequestFactoryServlet class contains the following code:
public class RFERequestFactoryServlet extends RequestFactoryServlet {
#Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws IOException, ServletException {
if (!userIsLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
else {
super.doPost(request, response);
}
}
private boolean userIsLoggedIn(final HttpServletRequest request) {
boolean result = false;
HttpSession session = request.getSession();
if (session != null) {
User user = (User)session.getAttribute("User");
result = user != null;
}
return result;
}
}
On the client side I needed to intercept every RequestFactory response to check for the SC_UNAUTHORIZED error. You have to tell the RequestFactory object to use a specific RequestTransport in the RequestFactory#initialize invocation, like this:
MyRequestFactory requestFactory = GWT.create(MyRequestFactory.class);
requestFactory.initialize(eventBus, new RFERequestTransport());
My RFERequestTransport class extends the DefaultRequestTransport class:
public class RFERequestTransport extends DefaultRequestTransport {
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
}
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
}
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
// the login processing goes here
}
else {
_requestCallback.onResponseReceived(request, response);
}
}
} // end of the RFERequestCallback class
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
}
}
When RequestFactory creates a request callback it calls my method, which creates my own version of a RequestCallback. If the user is logged in (as determined by the servlet) then it just performs the normal RequestFactory processing; otherwise, I go through the login process with the user. Part of the login process involves communication with the server to verify the login ... if the login is successful then I create an object on the server and store a reference to it in the "User" attribute - this is then checked in the userIsLoggedIn method in the servlet class.
Setup a filter in your web.xml so as every RF request is filtered to validate the session.
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>my.namespace.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/gwtRequest</url-pattern>
</filter-mapping>
Here you have an example class, checking if a certain parameter is in session which could be set in the login process to your app, this is just an example, you could use your own mechanism.
public class AuthFilter implements Filter {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
if (req.getSession().getAttribute("VALID_SESSION") == null) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
if (null != filterChain) {
filterChain.doFilter(req, resp);
}
}
}

gwt - servlet path + url

I need to read data from an xml file that is under the WAR directory.
I'm using RequestBuilder for creating the GET request.
It looks like this:
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,"customerRecord.xml");
try {
requestBuilder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
requestFailed(exception);
}
public void onResponseReceived(Request request,Response response) {
renderXML(response.getText());
}
});
} catch (RequestException ex) {
requestFailed(ex);
}
Now, the thing is that I don't want to load all of the data. I want to send a parameter that tells the server which part to bring, (let's say - how many lines of data) and then override the doGet method of the servlet and deal with the parameter.
I have 2 questions:
1) how do I declare the path of the servlet? where is the connection between the servlet and the request??
2) What do I write in the url of the RequestBuilder (instead of "customerRecord.xml")? do I need to refer to the servlet there or I can keep it like
May be You mean GWT Service?
You need to create 2 interfaces - Service and ServiceAsync and implementation of Service in server package (on same level as client package). Then You define implementation as servlet (in my JBoss 7.1 it just annotation. in older version servlet mapping):
#WebServlet(name="YourService", urlPatterns={"/%module%/YourService"})
public class YourServiceImpl extends RemoteServiceServlet implements YourService
in Your modeule.xml write:
<servlet path="/YourService" class="org.name.YourServiceImpl"/>
and in the end You can call this service from Your code
YourService.App.getInstance().getSomething(new AsyncCallback<Collection<Something>>() {
#Override
public void onFailure(Throwable caught) {
new MessagePopup("Error: " + caught.getMessage()).center();
}
#Override
public void onSuccess(Collection<Something> result) {
}
});
Interfaces You can create from Your beloved IDE. It's much simpler)
One think which still bothering me - I cannot specify path for servlet in another module.