Monday, November 10, 2014

GWTP Dispatch and Spring Security

GWT Applications and Spring Security
For some time ago I was struggling with GWTP based application, which I had to make work with Spring Security. Usually GWT web applications are one-page projects so that means there is no much Web-part from Spring Security:

Using JavaConfig in your WebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
 //Allowing all URLs as the security is only method-based (there is no login page per se)
 http.authorizeRequests().antMatchers("/**").permitAll();
 http.httpBasic().authenticationEntryPoint(entryPoint());
        //It's enabled by default for JavaConfig
 http.csrf().disable();

 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
}
The entryPoint() returns empty AuthenticationEntryPoint (authentication is implemented with GWTP presenter, hence there is no separate LoginForm)
Identical using XML:
<beans:bean class="com.jdsu.nse.mac.server.security.ActionAuthenticationEntryPoint" id="entryPoint">
<http entry-point-ref="entryPoint" use-expressions="true">
 <intercept-url access="permitAll()" pattern="/**">
        </session-management>
</http>
The communication with the server was implemented using Action pattern described on Google I/O (an implemented in GWTP). The trickiest part was to make Spring Security work with Action handlers. GWTP supports Spring as a DI on the server side so Guice had to be replaced with Spring (even though I'd prefer Guice over Spring). The crucial point to make it all work is to tell Spring Security to generate proxies for the classes (each particular ActionHandler implementation) as opposed to interface-based proxy generation.

Using JavaConfig annotate WebSecurityConfigurerAdapter with:
@EnableGlobalMethodSecurity(proxyTargetClass = true, securedEnabled = true)
Notice proxyTargetClass = true. Without this Spring Security will generate all proxies based on ActionHandler interface and GWTP won't be able to call any specific handler implementation for passed Action type.

The same in XML:
<global-method-security secured-annotations="enabled" proxy-target-class="true" />
Finally, to convert Spring Security exceptions to custom client exceptions you need to rewrite three classes from GWTP (basically copy/paste) - DispatchModuleHandlerModule and DispatchImpl.

Change default dispatchClass in your custom DispatchModule to SecureDispatchImpl implementation. Your application HandlerModule then would have to extend your custom HandlerModule. This way you can tell GWTP to use SecureDispatchModule:
public class SecureDispatchImpl extends AbstractDispatchImpl {
    @Autowired
    public SecureDispatchImpl(ActionHandlerValidatorRegistry actionHandlerValidatorRegistry) {
        super(actionHandlerValidatorRegistry);
    }

    public <A extends Action<R>, R extends Result> R execute(A action)
        throws ActionException, ServiceException {
        try {
     return super.execute(action);
 } catch (ServiceException e) {
            if (e.getCause() instanceof AccessDeniedException) {
         if (SecurityContextHolder.getContext().getAuthentication() instanceof 
                    AnonymousAuthenticationToken) {
             throw new AuthenticationException();
         } else {
             throw new AuthorizationException(e.getCause().getMessage());
         }
            }
            throw e;
 }
    }
}
For now I didn't find any better solution to override DispatchImpl.

P.S.: don't forget to make all your custom role names to have ROLE_ prefix. I've spent several hours before I found why my user with correct role wasn't allowed to call action handler annotated with the same role name (apparently it doesn't work without ROLE_ prefix).

Wednesday, November 20, 2013

GWTP-based Navigation Menu

One of the recent GWTP-based project's requirements was to implement navigation menu with support for currently selected navigation place. The project used nested presenter layout, where each of the nested presenters was a separate navigation item in the menu. Something like this
The SimpleNestedExample from GWTP describes very basic history/place navigation without support for currently revealed place. For more info about GWTP history/place management refer to GWTP wiki.

The first thing to implement is the container for navigation item links, which will know about currently revealed place. GWTP's place management is implemented on top of the GWT history management, hence the navigation container widget has to support item selection by history token (navigation token in the code sample) to be able to highlight current place.
 /**
  * Selects the navigation item by name token
  * 
  * @param navigationToken
  *            String parameter identifying the name token
  */
 public void selectNavigationItemByToken(String navigationToken) {
  if (navigationToken == null || navigationToken == "") {
   return;
  }

  NavigationItem navigationItem = this.navigationItems
    .get(navigationToken);

  if (navigationItem == null) {
   return;
  }

  deselectNavigationItem(this.selectedNavigationItem);
  this.selectedNavigationItem = navigationItem;
  selectNavigationItem(this.selectedNavigationItem);
 }
The requirements for the project added some constraints to navigation items, so we had to implement a separate NavigationItem class. For simple navigation it's sufficient to use plain InlineHyperlink with styling.

The interesting part in all this is how to handle navigation events and I must say, GWTP makes it very easy to implement. The only thing to do is to implement com.gwtplatform.mvp.client.proxy.NavigationHandler and simply call previously implemented selectNavigationItemByToken() method
 @Override
 public void onNavigation(NavigationEvent navigationEvent) {
  selectNavigationItemByToken(navigationEvent.getRequest().getNameToken());
 }
The last step is to initialize the navigation widget in the presenter, which contains this widget (in our project it was HeaderPresenter):
  1. Bind navigation widget to EventBus (usually inside onBind() method)
  2. this.addRegisteredHandler(NavigationEvent.getType(), this.getView()
        .getNavigationBar());
    
  3. Populate with all navigation items you want to be displayed in navigation menu (which are your custom name tokens for nested presenters). I'd suggest to do this in onReset() method as the header presenter is revealed only once and always stays visible.
  4. Select the navigation item based on the current place - onReset() will fit better for this task as well. The reason to have this line of code is that the navigation widget has not been created yet at the time of the first reveal so it didn't receive the initial NavigationEvent.
  5. final NavigationBar navigationBar = this.getView().getNavigationBar();
    navigationBar.selectNavigationItemByToken(this.placeManager
        .getCurrentPlaceRequest().getNameToken());
That's all it takes to implement Navigation menu with selected item support in GWTP.