Question on request wrapping

105 views
Skip to first unread message

Mohan

unread,
Mar 26, 2012, 2:31:55 AM3/26/12
to impala-users
Hi,

I am new to impala and wanted to check on how to configure
security in a web module. I have a project with a web module ( spring3
+ webflow ) and I am trying to use 'springSecurityFilterChain' to wrap
security around it. When I use 'springSecurityFilterChain', request
object gets wrapped as SecurityContextHolderAwareRequestWrapper and
its not an instance of ModuleHttpServletRequest. Since the request is
not an instance of ModuleHttpServletRequest, module mappers such as
'UrlPrefixRequestModuleMapper' are not able to map urls correctly.
Following is some of the relevant configuration.

// Filter class
public class LoginFilter extends BaseDelegatingFilterProxy{
@Override
protected String getBeanName(ServletRequest request) {
return "springSecurityFilterChain";
}
}

// all html/webflow requests are attached with login filter
<web:to-handler extension="html" servletName="useradmin-dispatcher"
filterNames="encoding-filter,loginFilter" />

Questions
1. Is this the correct way to configure security filter? If not can
any one give a hint on what is the correct way to configure the same?.
I have few existing applications which are all wired using
springSecurityFilterChain and want to leverage the same.

2. How can I get the modules working if any other framework wraps
requests into their custom classes leading to the same issue as above.

I tried following work around to get it to work out of curiosity. I
made custom build out of impala 1.0.2 to do the following. Pardon my
ignorance, but I was just trying to get it to work.

1. Any request that gets wrapped as MappedHttpServletRequest adds an
instance of
RequestModuleMapping to request object. Even if this request is
wrapped via custom wrapper on the way , its possible to identify
whether the request is of ModuleHttpServletRequest nature or not.

2. Any interested party can use RequestModuleMapping object from
request to implement a wrapper so that request can be an instance of
ModuleHttpServletRequest and the framework would pick it up fine.
Following is the sample for using springSecurityFilterChain

1. Ask spring not to provision servlet support
<security:http auto-config="true" servlet-api-provision="false">
....
</security:http>

2. Add servlet support as spring filter
<security:custom-filter ref="securityContextHolderAwareRequestFilter"
position="SERVLET_API_SUPPORT_FILTER"/>

3. Define a custom filter bean which can wrap the request into
something framework is aware of
<bean id="securityContextHolderAwareRequestFilter"
class="org.springbyexample.impala.support.ImapalaSecurityContextHolderAwareRequestFilter">
</bean>

4. public class ImapalaSecurityContextHolderAwareRequestFilter extends
SecurityContextHolderAwareRequestFilter {

@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {

RequestModuleMapping currentModuleMapping = (RequestModuleMapping)
req
.getAttribute("request.moduleMapping");

if
("true".equals(req.getAttribute("request.ModuleHttpServletRequest"))
&& null != currentModuleMapping) {

ImapalaSecurityContextHolderAwareRequestWrapper
securedImpalaRequestWrapper = new
ImapalaSecurityContextHolderAwareRequestWrapper(
(HttpServletRequest) req, currentModuleMapping, rolePrefix);

chain.doFilter(securedImpalaRequestWrapper, res);
} else {
super.doFilter(req, res, chain);
}
}

}

5. Define a wrapper which is an instance of ModuleHttpServletRequest
and implement ModuleHttpServletRequest interface based on
RequestModuleMapping from request.

public class ImapalaSecurityContextHolderAwareRequestWrapper extends
SecurityContextHolderAwareRequestWrapper implements
ModuleHttpServletRequest{

}


Thanks for your patience.

Phil Zoio

unread,
Mar 26, 2012, 4:35:16 AM3/26/12
to impala...@googlegroups.com
Hi Mohan,

Just to be clear, does your workaround actually work?

I'm bit unclear still why you need to create an extension of SecurityContextHolderAwareRequestWrapper which implements
ModuleHttpServletRequest

What happens if in your example you simply use the normal SecurityContextHolderAwareRequestFilter instead of the one
which which creates the Impala-specific request wrapper?

Just to take a step back, there are effectively two ways you can do the security filter.

1. Within web.xml, which takes it outside of the Impala module invocation
2. Within the module framework, as in your example below

In this case, normally what should happen would the the following:

1 the request is intercepted by ModuleProxyFilter declared in web.xml
2 the request is mapped to the relevant module
3 the request is handled within the module using the module specific filter chain, created using the 'web:to-handler'
definition within the web module
4 the filters within the module are invoked
5 the servlet within the module is invoked (provided the filters have caused chain.doFilter())

In your case, the security filter should be handled at point 4. At this point, Impala has already done all the mapping
that it need to do, so it should matter whether your HttpServletRequest implements ModuleHttpServletRequest or not.

If you can give me details on how application fails using the 'vanilla' configuration. Also, in doing so, could you
verify (using the call stack in your debugger) that the ModuleProxyFilter is invoking the security filter, which is
attempting to invoke your Spring MVC dispatcher servlet?

Phil

Mohan

unread,
Mar 26, 2012, 7:37:04 AM3/26/12
to impala-users

Thanks Phil, yes the workaround works.

Following is my web mapping declaration.

<web:mapping>
<web:to-module prefix="/useradmin" setContextPath="true" />
<web:to-handler extension="[none]" servletName="myapp-useradmin"
filterNames="encoding-filter,loginFilter" />
<web:to-handler extension="html" servletName="useradmin-
dispatcher"filterNames="encoding-filter,loginFilter" />
<web:to-handler extension="css" servletName="resources"
filterNames="loginFilter" />
<web:to-handler extension="jsp" servletName="useradmin-jsp"
filterNames="loginFilter" />
</web:mapping>



1. I invoke http://localhost:8080/myapp-host/useradmin/login.html that
looks for a tiles view by looking up resource /myapp-host/templates/
main.jsp which doesnt exist as the main.jsp is in useradmin module.
Relevant stack and details are as follows

a. Initial request ( /login.html) is processed by ModuleProxyFilter
and then passed on to ModuleHttpServiceInvoker which invokes filter
chain.
b. This triggers loginFilter leading to spring security to wrap
requests.
c. The call stack process to InternalModuleServlet.render() which
invokes DynamicTilesView.render()
d. This leads to dispatcher servlet issuing a forward request for
resource /templates/main.jsp
e. This forward request is again processed by ModuleProxyFilter -
>CompositeRequestModuleMapper->UrlPrefixRequestModuleMapper which is
not able to utilize SecurityContextHolderAwareRequestWrapper as its
not an instance of ModuleHttpServletRequest .

It appears that the forward request is being re-processed by
ModuleProxyFilter, did I make some configuration mistake? Following is
the relevant stack, let me know if you want me to post entire
configuration/stack.


=========================================================================================================================

UrlPrefixRequestModuleMapper.getModuleForRequest(HttpServletRequest)
line: 59
CompositeRequestModuleMapper.getModuleForRequest(HttpServletRequest)
line: 46
ModuleProxyFilter(BaseModuleProxyFilter).getModuleMapping(HttpServletRequest)
line: 92
ModuleProxyFilter(BaseModuleProxyFilter).doFilter(HttpServletRequest,
HttpServletResponse, ServletContext, FilterChain) line: 68
ModuleProxyFilter(BaseLockingProxyFilter).doFilter(ServletRequest,
ServletResponse, FilterChain) line: 77
ServletHandler$CachedChain.doFilter(ServletRequest, ServletResponse)
line: 1157
....
Dispatcher.forward(ServletRequest, ServletResponse, int) line: 327
Dispatcher.forward(ServletRequest, ServletResponse) line: 126
ServletTilesRequestContext.forward(String) line: 241
......

SecurityContextHolderAwareRequestFilter.doFilter(ServletRequest,
ServletResponse, FilterChain) line: 54
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
RequestCacheAwareFilter.doFilter(ServletRequest, ServletResponse,
FilterChain) line: 35
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
BasicAuthenticationFilter.doFilter(ServletRequest, ServletResponse,
FilterChain) line: 177
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
UsernamePasswordAuthenticationFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest,
ServletResponse, FilterChain) line: 187
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
LogoutFilter.doFilter(ServletRequest, ServletResponse, FilterChain)
line: 105
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
SecurityContextPersistenceFilter.doFilter(ServletRequest,
ServletResponse, FilterChain) line: 79
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest,
ServletResponse) line: 380
FilterChainProxy.doFilter(ServletRequest, ServletResponse,
FilterChain) line: 169
LoginFilter(BaseDelegatingFilterProxy).invokeDelegate(Filter,
ServletRequest, ServletResponse, FilterChain) line: 97
LoginFilter(BaseDelegatingFilterProxy).doFilter(ServletRequest,
ServletResponse, FilterChain) line: 58
InvocationChain.invoke(HttpServletRequest, HttpServletResponse,
FilterChain) line: 85
InvocationChain.doFilter(ServletRequest, ServletResponse) line: 97
CharacterEncodingFilter.doFilterInternal(HttpServletRequest,
HttpServletResponse, FilterChain) line: 88
CharacterEncodingFilter(OncePerRequestFilter).doFilter(ServletRequest,
ServletResponse, FilterChain) line: 76
InvocationChain.invoke(HttpServletRequest, HttpServletResponse,
FilterChain) line: 85
ModuleHttpServiceInvoker.invoke(HttpServletRequest,
HttpServletResponse, FilterChain) line: 116
ModuleProxyFilter(ModuleProxyFilter).processMapping(ServletContext,
HttpServletRequest, HttpServletResponse, FilterChain,
RequestModuleMapping, String) line: 70
ModuleProxyFilter(BaseModuleProxyFilter).doFilter(HttpServletRequest,
HttpServletResponse, ServletContext, FilterChain) line: 72
ModuleProxyFilter(BaseLockingProxyFilter).doFilter(ServletRequest,
ServletResponse, FilterChain) line: 77
ServletHandler$CachedChain.doFilter(ServletRequest, ServletResponse)
line: 1157
ServletHandler.handle(String, HttpServletRequest, HttpServletResponse,
int) line: 388
SecurityHandler.handle(String, HttpServletRequest,
HttpServletResponse, int) line: 216
SessionHandler.handle(String, HttpServletRequest, HttpServletResponse,
int) line: 182
WebAppContext(ContextHandler).handle(String, HttpServletRequest,
HttpServletResponse, int) line: 765
WebAppContext.handle(String, HttpServletRequest, HttpServletResponse,
int) line: 418

Phil Zoio

unread,
Mar 26, 2012, 11:07:55 AM3/26/12
to impala...@googlegroups.com
Mohan,

I can understand the problem now, you have explained it well.

Yes, the request is sent again from through the ModuleProxyFilter. This is because JSP invocation is handled through a
RequestDispatcher instance, which is provided by the servlet container, not Impala (this takes place in the
DynamicTilesView). Your problem wouldn't occur if another view technology is used which doesn't use the
RequestDispatcher mechanism.

So, yes, there does seem to be a limitation, as you have identified, to the way you can wrap requests within Impala from
within the module based dispatcher.

Under the circumstances your approach looks correct (although not optimal, as it would be nice not to have to create to
an Impala-specific security filter).

I have raised a ticket for this - http://code.google.com/p/impala/issues/detail?id=379

Would you be interested in submitting a patch?

Phil

Reply all
Reply to author
Forward
0 new messages