3

I have a SimpleMappingExceptionResolver to redirect every unhandled exception.

 @Bean public SimpleMappingExceptionResolver exceptionResolver() {
           SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
           resolver.setDefaultErrorView("general-error");
           resolver.setWarnLogCategory(TamponException.class.getName());
           return resolver;
}

As soon as I implemented Spring security, I realized that I need to exclude the AccessDeniedException:

resolver.setExcludedExceptions(AccessDeniedException.class);

Now I'm implementing Spring Web Flow. SWF is wrapping those essential AccessDeniedExceptions in FlowExecutionException. This combination breaks Spring Security as those wrapped exceptions are now caught by the SimpleMappingExceptionResolver. I could exclude also the FlowExecutionException, but this is not what I want.

How do I properly solve this problem?

My next thaught would be implementing a HandlerExceptionResolver which delegates resolveException() only if the unwrapped Exception is not a AccessDeniedException. But I'm wondering if there doesn't exist something ready to use for the combination SWF, Security and a HandlerExceptionResolver.

Markus Malkusch
  • 7,738
  • 2
  • 38
  • 67

1 Answers1

2

I'm using a configuration similar to yours, with Spring webflow and Spring security. To handle exceptions I use webflow handling instead of a SimpleMappingExceptionResolver and this works very well for me.

as a start you need a global xml flow that handle the exceptions, this flow will be used as "parent" of all your other flows. or you could also include directly the global transition and view-state in your flows:

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
      http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
      abstract="true">

    <persistence-context/>

    <view-state id="generalException" view="../views/exception/generalException.xhtml">
        <on-entry>
            <evaluate expression="exceptionManager.extractMessages(flowExecutionException, rootCauseException)" result="viewScope.exc"/>
        </on-entry>
    </view-state>

    <global-transitions>
        <transition on-exception="java.lang.Exception" to="generalException"/>
    </global-transitions>

</flow>

The class ExceptionManager is used only to format the exception in a readable way, specially in my case BatchUpdateException that needs the next() method to be called to know the source of the exception:

@Service("exceptionManager")
public class ExceptionManagerImpl {

    public Map<String, String> extractMessages(Exception e, Exception root)
    {
        Map<String, String> out = new HashMap<String, String>();

        out.put("exc_message", e.getClass().toString() + ": " + e.getMessage());
        out.put("exc_details", formatStackTrace(e.getStackTrace()));
        out.put("root_message", root.getClass().toString() + ": " + root.getMessage());
        out.put("root_details", formatStackTrace(root.getStackTrace()));
        if (root instanceof BatchUpdateException)
        {
            out.put("batch_message", ((BatchUpdateException)root).getNextException().getClass().toString() + ": " + ((BatchUpdateException)root).getNextException().getMessage());
        }

        return out;
    }

    public String formatStackTrace(StackTraceElement[] elements)
    {
        String out = "";
        for (StackTraceElement ste: elements)
            out += ste.toString() + "<br/>";
        return out;
    }
}

in this way all the unhandled exception will display into a JSF page, or whatever you use for views. AccessDeniedException goes normally trough Spring security in my system with this implementation. You could also specify different behaviours for different exception.

I hope it helps, have a good day,

Mattia

malavock
  • 341
  • 1
  • 5
  • 21