Hi
I have the following web configuration where /** is secured. When I get request for the resources used on a web page (ie image and javascript files) I get the stacktrace listed below. In the debugger I can see that the function in AccessControlFilter protected Subject getSubject(ServletRequest request, ServletResponse response) returns null, but the session variables content looks fine. (called from AuthenticationFilter.isAccessAllowed()) All requests for jsf pages is fine.
I am running 0.9.0-RC2
Any suggestions?
JSecurityFilter
org.jsecurity.web.servlet.JSecurityFilter
config
#NOTE: This config looks pretty long - but its not - its only 5 lines of actual config.
# Everything else is just heavily commented to explain things in-depth. Feel free to delete any
# comments that you don't want to read from your own configuration ;)
#
# Any commented values below are JSecurity's defaults. If you want to change any values, you only
# need to uncomment the lines you want to change.
[main]
# The 'main' section defines JSecurity-wide configuration.
#
# Session Mode: By default, JSecurity's Session infrastructure in a web environment will use the
# Servlet container's HttpSession. However, if you need to share session state across client types
# (e.g. Web MVC plus Java Web Start or Flash), or are doing distributed/shared Sessions for
# Single Sign On, HttpSessions aren't good enough. You'll need to use JSecurity's more powerful
# (and client-agnostic) session management. You can enable this by uncommenting the following line
# and changing 'http' to 'jsecurity'
#
#securityManager = org.jsecurity.web.DefaultWebSecurityManager
#securityManager.sessionMode = jsecurity
securityManager.sessionMode = http
[filters]
# This section defines the 'pool' of all Filters available to the url path definitions in the [urls] section below.
#
# The following commented values are already provided by JSecurity by default and are immediately usable
# in the [urls] definitions below. If you like, you may override any values by uncommenting only the lines
# you need to change.
#
# Each Filter is configured based on its functionality and/or protocol. You should read each
# Filter's JavaDoc to fully understand what each does and how it works as well as how it would
# affect the user experience.
#
# Form-based Authentication filter:
#authc = FormAuthenticationFilter
#authc.url = /login.jsp
#authc.usernameParam = username
#authc.passwordParam = password
#authc.rememberMeParam = rememberMe
#authc.successUrl = /login.jsp
#authc.failureKeyAttribute = FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME
#
# Http BASIC Authentication filter:
#authcBasic = BasicHttpAuthenticationFilter
authcBasic.applicationName = ES Inventorysystem authen
#
# Roles filter: requires the requesting user to have one or more roles for the request to continue.
# If they do not have the specified roles, they are redirected to the specified URL.
#roles = RolesAuthorizationFilter
#roles.url =
# (note the above url is null by default, which will cause an HTTP 403 (Access Denied) response instead
# of redirecting to a page. If you want to show a 'nice page' instead, you should specify that url.
#
# Permissions filter: requires the requesting user to have one or more permissions for the request to
# continue, and if they do not, redirects them to the specified URL.
#perms = PermissionsAuthorizationFilter
#perms.url =
# (note the above url is null by default, which will cause an HTTP 403 (Access Denied) response instead
# of redirecting to a page. If you want to show a 'nice page' instead, you should specify that url. Many
# applications like to use the same url specified in roles.url above.
#
#
# Define your own filters here. To properly handle url path matching (see the [urls] section below), your
# filter should extend the PathMatchingFilter abstract class.
[urls]
# This section defines url path mappings. Each mapping entry must be on a single line and conform to the
# following representation:
#
# ant_path_expression = path_specific_filter_chain_definition
#
# For any request that matches a specified path, the corresponding value defines a comma-delimited chain of
# filters to execute for that request.
#
# This is incredibly powerful in that you can define arbitrary filter chains for any given request pattern
# to greatly customize the security experience.
#
# The path_specific_filter_chain_definition must match the following format:
#
# filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
#
# where 'filterN' is the name of an filter defined above in the [filters] section and
# '[optional_configN]' is an optional bracketed string that has meaning for that particular filter for
# _that particular path_. If the filter does not need specific config for that url path, you may
# discard the brackets - that is, filterN[] just becomes filterN.
#
# And because filter tokens define chains, order matters! Define the tokens for each path pattern
# in the order you want them to filter (comma-delimited).
#
# Finally, each filter is free to handle the response however it wants if its necessary
# conditions are not met (redirect, HTTP error code, direct rendering, etc). Otherwise, it is expected to allow
# the request to continue through the chain on to the final destination view.
#
# Examples:
#
# To illustrate chain configuration, look at the /account/** mapping below. This says
# "apply the above 'authcBasic' filter to any request matching the '/account/**' pattern". Since the
# 'authcBasic' filter does not need any path-specific config, it doesn't have any config brackets [].
#
# The /remoting/** definition on the other hand uses the 'roles' and 'perms' filters which do use
# bracket notation. That definition says:
#
# "To access /remoting/** urls, ensure that the user is first authenticated ('authcBasic'), then ensure that user
# has the 'b2bClient' role, and then finally ensure that they have the 'remote:invoke:lan,wan' permission."
#
# (Note that because elements within brackets [ ] are comma-delimited themselves, we needed to escape the permission
# actions of 'lan,wan' with quotes. If we didn't do that, the permission filter would interpret
# the text between the brackets as two permissions: 'remote:invoke:lan' and 'wan' instead of the
# single desired 'remote:invoke:lan,wan' token. So, you can use quotes wherever you need to escape internal
# commas.)
#/docs/** = authc
#/** = authc,roles[esAdmin]
/** = authcBasic,roles[esAdmin]
#/newItem** = authcBasic
#/security/** = authcBasic
#/registration/** = authcBasic,roles[esreg]
#/remoting/** = authcBasic, roles[b2bClient], perms[remote:invoke:"lan,wan"]
And the stacktrace for RC2:
javax.servlet.ServletException: Filter execution resulted in an unexpected Exception (not IOException or ServletException as the Filter api recommends). Wrapping in ServletException and propagating.
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.cleanup(AdviceFilter.java:188)
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:146)
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.FilterChainWrapper.doFilter(FilterChainWrapper.java:57)
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
15:47:06,239 ERROR [STDERR] at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
15:47:06,239 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
15:47:06,239 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
15:47:06,239 ERROR [STDERR] at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
15:47:06,240 ERROR [STDERR] at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
15:47:06,240 ERROR [STDERR] at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
15:47:06,240 ERROR [STDERR] at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:156)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:543)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
15:47:06,240 ERROR [STDERR] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
15:47:06,240 ERROR [STDERR] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
15:47:06,240 ERROR [STDERR] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
15:47:06,241 ERROR [STDERR] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
15:47:06,241 ERROR [STDERR] at java.lang.Thread.run(Thread.java:619)
15:47:06,241 ERROR [STDERR] Caused by: java.lang.NullPointerException
15:47:06,241 ERROR [STDERR] at org.jsecurity.web.filter.authc.AuthenticationFilter.isAccessAllowed(AuthenticationFilter.java:72)
15:47:06,241 ERROR [STDERR] at org.jsecurity.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:145)
15:47:06,241 ERROR [STDERR] at org.jsecurity.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:175)
15:47:06,241 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:129)
15:47:06,241 ERROR [STDERR] ... 25 more
Stacktrace when using current SVN (25/08 2008)
10:22:17,281 ERROR [[FacesServlet]] Servlet.service() for servlet FacesServlet threw exception
java.lang.IllegalStateException: No ServletRequest found in ThreadContext. Make sure WebUtils.bind() is being called. (typically called by JSecurityFilter) This could also happen when running integration tests that don't properly call WebUtils.bind().
at org.jsecurity.web.WebUtils.getRequiredServletRequest(WebUtils.java:325)
at org.jsecurity.web.DefaultWebSecurityManager.bind(DefaultWebSecurityManager.java:233)
at org.jsecurity.mgt.DefaultSecurityManager.getSubject(DefaultSecurityManager.java:418)
at org.jsecurity.mgt.DefaultSecurityManager.getSubject(DefaultSecurityManager.java:424)
at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:367)
at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:156)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:543)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
10:22:26,349 ERROR [STDERR] javax.servlet.ServletException: Filter execution resulted in an unexpected Exception (not IOException or ServletException as the Filter api recommends). Wrapping in ServletException and propagating.
10:22:26,349 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.cleanup(AdviceFilter.java:188)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:146)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.FilterChainWrapper.doFilter(FilterChainWrapper.java:57)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:105)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:135)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.FilterChainWrapper.doFilter(FilterChainWrapper.java:57)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
10:22:26,350 ERROR [STDERR] at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
10:22:26,350 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
10:22:26,350 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
10:22:26,350 ERROR [STDERR] at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
10:22:26,350 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
10:22:26,350 ERROR [STDERR] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
10:22:26,351 ERROR [STDERR] at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
10:22:26,351 ERROR [STDERR] at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
10:22:26,351 ERROR [STDERR] at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:156)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:543)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
10:22:26,351 ERROR [STDERR] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
10:22:26,351 ERROR [STDERR] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
10:22:26,351 ERROR [STDERR] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
10:22:26,351 ERROR [STDERR] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
10:22:26,351 ERROR [STDERR] at java.lang.Thread.run(Thread.java:619)
10:22:26,352 ERROR [STDERR] Caused by: java.lang.NullPointerException
10:22:26,352 ERROR [STDERR] at org.jsecurity.web.filter.authz.RolesAuthorizationFilter.isAccessAllowed(RolesAuthorizationFilter.java:51)
10:22:26,352 ERROR [STDERR] at org.jsecurity.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:145)
10:22:26,352 ERROR [STDERR] at org.jsecurity.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:175)
10:22:26,352 ERROR [STDERR] at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:129)
10:22:26,352 ERROR [STDERR] ... 29 more
Sample Test Case/App
We definitely want to help you work this problem out. Both Les and I have looked at this issue some and can't see why it would happen by statically examining the code. Is it possible that you could send us a small test case or sample app that replicates this behavior? Perhaps one we could drop in Tomcat or Jetty? I'd be happy to debug the code and see if I could figure out what might be causing it!
Re: Error after updating to 0.9.0-RC2
Hello,
I'm not entirely sure how this exception could even be possible. For example, look at the following source code (this is in JSecurityFilter):
WebUtils.bind(request);
WebUtils.bind(response);
ThreadContext.bind(getSecurityManager());
ThreadContext.bind(getSecurityManager().getSubject());
The first two calls bind the request and response to the ThreadContext. The first call's request argument is guaranteed not to be null because we explicitly create a wrapper object around the servlet container's request (using the Java 'new' operator). So that can't be null and that the call returns successfully means it is correctly bound to the thread.
The 4th/last line above, the one that is causing your exception, uses the ThreadContext to get the same (non-null) ServletRequest that was bound 3 calls earlier! Here is the relevant part of the exception:
at org.jsecurity.web.WebUtils.getRequiredServletRequest(WebUtils.java:325)
at org.jsecurity.web.DefaultWebSecurityManager.bind(DefaultWebSecurityManager.java:233)
at org.jsecurity.mgt.DefaultSecurityManager.getSubject(DefaultSecurityManager.java:418)
at org.jsecurity.mgt.DefaultSecurityManager.getSubject(DefaultSecurityManager.java:424)
at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:367)
So, as you can see, it doesn't seem possible that this can even occur since the first call binds the non-null ServletRequest object. But the exception is thrown because the ThreadContext.get(SERVLET_REQUEST_KEY) is indeed returning null. I'm baffled as to how this is possible. I wonder if this is related at all to JSF issues? Is there some funny thread swapping stuff going on?
Also, what does your filter mapping definitions in web.xml look like?