You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Stephen McCants <st...@hcs.us.com> on 2013/07/26 20:21:28 UTC

Shiro "clearing" POST content?

Hello All,
     I'm using Shiro to ensure that only authorized people can performs 
POSTs on my RESTlet application.  Unfortunately, I've run into a strange 
problem.  If I run without Shiro and my application handles the POSTs 
correctly.  However, if I put Shiro in place the content of the POST 
(XML in this case) becomes unreadable.  To try and simplify the problem, 
I even set Shiro to use the anonymous filter, but it still fails.

Here is the error I'm receiving when I try to parse the incoming XML:

Caused by: java.io.IOException: Couldn't read the XML representation. 
Premature end of file.
         at 
org.restlet.ext.xml.DomRepresentation.getDocument(DomRepresentation.java:175)
         at 
org.restlet.ext.xml.XmlRepresentation.evaluate(XmlRepresentation.java:273)
         at 
org.restlet.ext.xml.XmlRepresentation.internalEval(XmlRepresentation.java:555)
         ... 81 more

Here is my shiro.ini:

[main]
# Take 2 on a shared cache/Single Sign On that can be used by both REST 
and Schedule.
# Based on F_A_V's instructions from here:
# 
http://shiro-user.582556.n2.nabble.com/Shiro-and-multiple-wars-within-the-same-Servlet-Container-td5560737.html

# Cache for single sign on
ssoCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
ssoCacheManager.cacheManagerConfigFile = classpath:ehcache.xml
securityManager.cacheManager = $ssoCacheManager

# DAO for single sign on
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager

# 
https://cwiki.apache.org/confluence/display/SHIRO/Session+Management#SessionManagement-SessionTimeout
# this sets up the session purge. Sessions inactive for over an hour will
# be purged from the database. the interval is set in milliseconds.
sessionValidationScheduler = 
org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 60000
sessionValidationScheduler.sessionManager = $sessionManager
securityManager.sessionManager.sessionValidationScheduler = 
$sessionValidationScheduler
securityManager.sessionManager.sessionValidationSchedulerEnabled = true

# cookie for single sign on
# this sets up the session cookie. the name is the cookie name
# and the path is the cookie path. by setting the path to / we
# can use it across domains. ajax will automatically pick it up
# from the browser and send it with all calls to REST.
# using the default session name JSESSIONID but anything can
# be used.
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.path = /
securityManager.sessionManager.sessionIdCookie = $cookie

# authc is the form based authentication filter from shiro
# the usernameParam and passwordParam below specify that the
# form submitted will have will have inputs of those names
# the login url is the login page.
# If the login attempt fails, the resulting AuthenticationException fully
# qualified class name will be set as a request attribute under the 
failureKeyAttribute key.
# This can be used as an i18n key or lookup mechanism to explain to the 
user
# why their login attempt failed (e.g. no account, incorrect password, 
etc).
authc.usernameParam = j_username
authc.passwordParam = j_password
authc.loginUrl = /schedule_dev/login.jsp
#authc.successUrl = /index.html
authc.failureKeyAttribute = shiroLoginFailure

# Logout filter configuration (b/c it sends us off the bad places)
logout.redirectUrl = /schedule_dev/login.jsp?logout=true

# This is the connection information to the datbase
# that will be used for authentication. Where
# the user names and passwords are stored.
# TODO move this OUT of the shiro.ini so that it isn't part of the WAR 
file. (WTL-141)
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = XXXXX
ds.databaseName = webtl

# the authenticationQuery is the sql used to get the password from the db.
#jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm = com.hcs.webtl.shiro.realm.WebTimelineJdbcRealm
jdbcRealm.dataSource = $ds
jdbcRealm.authenticationQuery = SELECT password FROM webtl.users where 
email_address = ?

# all passwords are in the clear now but probably should be encrypted.
# this is the start of that effort.
#sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
#jdbcRealm.credentialsMatcher = $sha256Matcher

[urls]
/** = anon

Below is my web.xml that sets Shiro up:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

     <display-name>XXXXXX</display-name>

     <!-- Restlet Application -->
     <context-param>
<param-name>org.restlet.application</param-name>
             <param-value>
                com.hcs.webtl.rest.MainApplication
             </param-value>
     </context-param>
     <!-- Big Memory Go license file for EH Cache -->
     <context-param>
<param-name>com.tc.productkey.path</param-name>
<param-value>terracotta-license.key</param-value>
     </context-param>

     <!-- Restlet Adapter -->
     <servlet>
<servlet-name>ServerServlet</servlet-name>

         <servlet-class>
            org.restlet.ext.servlet.ServerServlet
         </servlet-class>
     </servlet>

     <!-- Catch all requests -->
     <servlet-mapping>
<servlet-name>ServerServlet</servlet-name>
         <url-pattern>/*</url-pattern>
     </servlet-mapping>

     <!-- Shriro security setup -->
     <!-- no init-param means load the INI config from 
classpath:shiro.ini -->
     <listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
     </listener>

     <!-- no init-param means load the INI config from 
classpath:shiro.ini -->
     <filter>
<filter-name>securityFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
     </filter>

     <filter-mapping>
<filter-name>securityFilter</filter-name>
         <url-pattern>/*</url-pattern>
         <dispatcher>REQUEST</dispatcher>
         <dispatcher>FORWARD</dispatcher>
         <dispatcher>INCLUDE</dispatcher>
     </filter-mapping>

     <!-- Initialize data cleanup listener -->
     <listener>
<listener-class>com.hcs.data.background.BackgroundContextListener</listener-class>
     </listener>
</web-app>

I could post my ehcache.xml, but I don't think it matters here.

Any thoughts?  I'm still trying to debug it, but I'm at a bit of a loss.

Thanks in advance!

Sincerely,
     Stephen McCants

-- 
Stephen McCants
Senior Software Engineer
Healthcare Control Systems
1-877-877-8795 x116


Re: Shiro "clearing" POST content?

Posted by Stephen McCants <st...@hcs.us.com>.
Hi Jared,
     Thanks for your reply.  This is the solution I'm going with, 
because I can set it to "text/xml" and then set noSessionCreation filter 
and make things work as desired.  Sadly, that didn't occur to me until 
after I'd implemented and tested a more complex solution that involved 
getting a session, using that cookie and then logging out (deleting the 
session).  (We're a little worried about session accumulation from the 
automated source.)
     Thanks!

         --Stephen

On 7/30/2013 3:36 PM, Jared Bunting wrote:
>
> My first thought is that this behavior of trying to read the POST 
> content only makes sense if the request is form data.  From that I am 
> assuming that your request either comes in with a form data content 
> type, or it comes in with no content-type header and tomcat is 
> assuming form data.  I'm mostly guessing the second.  If that's the 
> case, try posting with an appropriate content type.
>
> If that solves the issue and you still want to support the no content 
> type specified scenario, add a filter in front of shiro that sets a 
> default content type.
>
> On Jul 30, 2013 12:03 PM, "Stephen McCants" 
> <stephen.mccants@hcs.us.com <ma...@hcs.us.com>> wrote:
>
>     I've looked at using the noSessionCreation filter, but that
>     doesn't prevent the code from consuming the POST content looking
>     for a session that might exist.  Is there a filter that would
>     prevent Shiro from not even looking for a session id?
>
>     Thanks!
>
>     Sincerely,
>
>     Stephen
>
>     -- 
>     Stephen McCants
>     Senior Software Engineer
>     Healthcare Control Systems
>     1-877-877-8795 x116 <tel:1-877-877-8795%20x116>
>


-- 
Stephen McCants
Senior Software Engineer
Healthcare Control Systems
1-877-877-8795 x116


Re: Shiro "clearing" POST content?

Posted by Jared Bunting <ja...@peachjean.com>.
My first thought is that this behavior of trying to read the POST content
only makes sense if the request is form data.  From that I am assuming that
your request either comes in with a form data content type, or it comes in
with no content-type header and tomcat is assuming form data.  I'm mostly
guessing the second.  If that's the case, try posting with an appropriate
content type.

If that solves the issue and you still want to support the no content type
specified scenario, add a filter in front of shiro that sets a default
content type.
On Jul 30, 2013 12:03 PM, "Stephen McCants" <st...@hcs.us.com>
wrote:

> I've looked at using the noSessionCreation filter, but that doesn't
> prevent the code from consuming the POST content looking for a session that
> might exist.  Is there a filter that would prevent Shiro from not even
> looking for a session id?
>
> Thanks!
>
> Sincerely,
>
> Stephen
>
> --
> Stephen McCants
> Senior Software Engineer
> Healthcare Control Systems
> 1-877-877-8795 x116
>
>

Re: Shiro "clearing" POST content?

Posted by Stephen McCants <st...@hcs.us.com>.
I've looked at using the noSessionCreation filter, but that doesn't 
prevent the code from consuming the POST content looking for a session 
that might exist.  Is there a filter that would prevent Shiro from not 
even looking for a session id?

Thanks!

Sincerely,

Stephen

-- 
Stephen McCants
Senior Software Engineer
Healthcare Control Systems
1-877-877-8795 x116


Re: Shiro "clearing" POST content?

Posted by Stephen McCants <st...@hcs.us.com>.
Hello All,

So I've dug in deeper and decided on a course of action.  When a POST is 
coming in on a new connection (no session ID in the cookies or URL) 
Shiro calls request.getParameter(name) looking for the Session ID.  This 
results in org.apache.catalina.connector.Request.parseParameters() (part 
of Tomcat) consuming the POST input stream.

That is fine, except that after Request.parseParameter() is done, the 
POST body data is thrown away if it wasn't loaded into the parameters.  
Since I'm sending XML data, nothing is successfully loaded into the 
parameters, so the data is lost and my RESTlet ServerResource has no way 
of processing it.

This only affects POSTs because they are the only type by default in 
Tomcat's |parseBodyMethods |configuration option.

So, our current plan to solve this problem is to start each connection 
with a GET call that will return (among other data) a Session ID 
cookie.  We can then use this cookie on POST calls to prevent Shiro from 
trying to fetch the Parameters from the POST body and thereby consuming it.

Any thoughts on this particular problem and/or solution would be welcome.

Thanks!

Sincerely,
Stephen

-- 
Stephen McCants
Senior Software Engineer
Healthcare Control Systems
1-877-877-8795 x116


Re: Shiro "clearing" POST content?

Posted by Stephen McCants <st...@hcs.us.com>.
Hi All,

I've dug a little deeper and I see the problem - not sure what to do 
about it, though.  Maybe someone on the list will have a good idea or 
this will help someone who runs into this problem in the future.

I have a RESTlet application which is protected by Shiro.  Another 
program POSTs to the RESTlet App to create/update resources. However, 
this POSTer program creates a new connection every time it POSTs, so it 
never has a Session ID.

Shiro, however, checks for a session ID (even under the Anonymous 
filter).   First it checks the cookies, then it checks the URL and 
lastly, if and only if it is a POST, it will read the content looking 
for the Session ID.

This is what causes my problem.  After it has read the content, my 
application Resource tries to read the content from the stream, but 
can't since the stream's content has already been consumed. 
Unfortunately, the stream doesn't support reset().

Is there a way to tell Shiro not to read a POST's content?  I'm not 
concerned about tracking the POSTer application with a Session ID, 
although that is an option.

The determination to read the POST content is made in 
org.apache.shiro.web.session.mgt.DefaultWebSessionManager.getReferencedSessionId(...) 
by looking at the value of 
org.apache.catalina.connector.Connector.parseBodyMethodsSet.

I could override DefaultWebSessionManager, I suppose, but that is not my 
first choice and I'm unsure what that might break (logins?).

Thanks for any suggestions.

Sincerely,
     Stephen McCants

On 7/26/2013 1:21 PM, Stephen McCants wrote:
> Hello All,
>     I'm using Shiro to ensure that only authorized people can performs 
> POSTs on my RESTlet application.  Unfortunately, I've run into a 
> strange problem.  If I run without Shiro and my application handles 
> the POSTs correctly.  However, if I put Shiro in place the content of 
> the POST (XML in this case) becomes unreadable.  To try and simplify 
> the problem, I even set Shiro to use the anonymous filter, but it 
> still fails.
>
> Here is the error I'm receiving when I try to parse the incoming XML:
>
> Caused by: java.io.IOException: Couldn't read the XML representation. 
> Premature end of file.
>         at 
> org.restlet.ext.xml.DomRepresentation.getDocument(DomRepresentation.java:175)
>         at 
> org.restlet.ext.xml.XmlRepresentation.evaluate(XmlRepresentation.java:273)
>         at 
> org.restlet.ext.xml.XmlRepresentation.internalEval(XmlRepresentation.java:555)
>         ... 81 more
>
> Here is my shiro.ini:
>
> [main]
> # Take 2 on a shared cache/Single Sign On that can be used by both 
> REST and Schedule.
> # Based on F_A_V's instructions from here:
> # 
> http://shiro-user.582556.n2.nabble.com/Shiro-and-multiple-wars-within-the-same-Servlet-Container-td5560737.html
>
> # Cache for single sign on
> ssoCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
> ssoCacheManager.cacheManagerConfigFile = classpath:ehcache.xml
> securityManager.cacheManager = $ssoCacheManager
>
> # DAO for single sign on
> sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
> sessionManager = 
> org.apache.shiro.web.session.mgt.DefaultWebSessionManager
> sessionManager.sessionDAO = $sessionDAO
> securityManager.sessionManager = $sessionManager
>
> # 
> https://cwiki.apache.org/confluence/display/SHIRO/Session+Management#SessionManagement-SessionTimeout
> # this sets up the session purge. Sessions inactive for over an hour will
> # be purged from the database. the interval is set in milliseconds.
> sessionValidationScheduler = 
> org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
> sessionValidationScheduler.interval = 60000
> sessionValidationScheduler.sessionManager = $sessionManager
> securityManager.sessionManager.sessionValidationScheduler = 
> $sessionValidationScheduler
> securityManager.sessionManager.sessionValidationSchedulerEnabled = true
>
> # cookie for single sign on
> # this sets up the session cookie. the name is the cookie name
> # and the path is the cookie path. by setting the path to / we
> # can use it across domains. ajax will automatically pick it up
> # from the browser and send it with all calls to REST.
> # using the default session name JSESSIONID but anything can
> # be used.
> cookie = org.apache.shiro.web.servlet.SimpleCookie
> cookie.name = JSESSIONID
> cookie.path = /
> securityManager.sessionManager.sessionIdCookie = $cookie
>
> # authc is the form based authentication filter from shiro
> # the usernameParam and passwordParam below specify that the
> # form submitted will have will have inputs of those names
> # the login url is the login page.
> # If the login attempt fails, the resulting AuthenticationException fully
> # qualified class name will be set as a request attribute under the 
> failureKeyAttribute key.
> # This can be used as an i18n key or lookup mechanism to explain to 
> the user
> # why their login attempt failed (e.g. no account, incorrect password, 
> etc).
> authc.usernameParam = j_username
> authc.passwordParam = j_password
> authc.loginUrl = /schedule_dev/login.jsp
> #authc.successUrl = /index.html
> authc.failureKeyAttribute = shiroLoginFailure
>
> # Logout filter configuration (b/c it sends us off the bad places)
> logout.redirectUrl = /schedule_dev/login.jsp?logout=true
>
> # This is the connection information to the datbase
> # that will be used for authentication. Where
> # the user names and passwords are stored.
> # TODO move this OUT of the shiro.ini so that it isn't part of the WAR 
> file. (WTL-141)
> ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
> ds.serverName = localhost
> ds.user = root
> ds.password = XXXXX
> ds.databaseName = webtl
>
> # the authenticationQuery is the sql used to get the password from the 
> db.
> #jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
> jdbcRealm = com.hcs.webtl.shiro.realm.WebTimelineJdbcRealm
> jdbcRealm.dataSource = $ds
> jdbcRealm.authenticationQuery = SELECT password FROM webtl.users where 
> email_address = ?
>
> # all passwords are in the clear now but probably should be encrypted.
> # this is the start of that effort.
> #sha256Matcher = 
> org.apache.shiro.authc.credential.Sha256CredentialsMatcher
> #jdbcRealm.credentialsMatcher = $sha256Matcher
>
> [urls]
> /** = anon
>
> Below is my web.xml that sets Shiro up:
>
> <?xml version="1.0" encoding="ISO-8859-1"?>
> <!DOCTYPE web-app PUBLIC
>    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
>    "http://java.sun.com/dtd/web-app_2_3.dtd">
> <web-app>
>
>     <display-name>XXXXXX</display-name>
>
>     <!-- Restlet Application -->
>     <context-param>
> <param-name>org.restlet.application</param-name>
>             <param-value>
>                com.hcs.webtl.rest.MainApplication
>             </param-value>
>     </context-param>
>     <!-- Big Memory Go license file for EH Cache -->
>     <context-param>
> <param-name>com.tc.productkey.path</param-name>
> <param-value>terracotta-license.key</param-value>
>     </context-param>
>
>     <!-- Restlet Adapter -->
>     <servlet>
> <servlet-name>ServerServlet</servlet-name>
>
>         <servlet-class>
>            org.restlet.ext.servlet.ServerServlet
>         </servlet-class>
>     </servlet>
>
>     <!-- Catch all requests -->
>     <servlet-mapping>
> <servlet-name>ServerServlet</servlet-name>
>         <url-pattern>/*</url-pattern>
>     </servlet-mapping>
>
>     <!-- Shriro security setup -->
>     <!-- no init-param means load the INI config from 
> classpath:shiro.ini -->
>     <listener>
> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> 
>
>     </listener>
>
>     <!-- no init-param means load the INI config from 
> classpath:shiro.ini -->
>     <filter>
> <filter-name>securityFilter</filter-name>
> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
>     </filter>
>
>     <filter-mapping>
> <filter-name>securityFilter</filter-name>
>         <url-pattern>/*</url-pattern>
>         <dispatcher>REQUEST</dispatcher>
>         <dispatcher>FORWARD</dispatcher>
>         <dispatcher>INCLUDE</dispatcher>
>     </filter-mapping>
>
>     <!-- Initialize data cleanup listener -->
>     <listener>
> <listener-class>com.hcs.data.background.BackgroundContextListener</listener-class> 
>
>     </listener>
> </web-app>
>
> I could post my ehcache.xml, but I don't think it matters here.
>
> Any thoughts?  I'm still trying to debug it, but I'm at a bit of a loss.
>
> Thanks in advance!
>
> Sincerely,
>     Stephen McCants
>


-- 
Stephen McCants
Senior Software Engineer
Healthcare Control Systems
1-877-877-8795 x116