Announcement Announcement Module
Collapse
No announcement yet.
Hibernate based AuthenticationDao issues Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate based AuthenticationDao issues

    Hey everyone,

    I've got a webapp that I've implemented a Hibernate based AuthenticationDao for to make it easier to manage users. But I'm having some problems with it and mod_jk integration it seems. After the webapp has been up for a day or so and working fine all of a sudden Hibernate starts throwing LazyInitializationExceptions. It's really weird, because it seems like Acegi is trying to load a SecurityContext or something even if the user has never logged in or even visited the site before. The full exception they are getting is below. The strange thing is that if you bypass apache the mod_jk connector and go straight to the tomcat url everything works fine. So somehow mod_jk is sending invalid session data or something like that hibernate tries to load but can't.

    Has anyone tried to create a Hibernate AuthenticationDao before and run into anything similar?

    Thanks,
    Rich

    58861283 [TP-Processor3] ERROR org.hibernate.LazyInitializationException - could not initialize proxy - the owning Session was closed
    org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
    at org.hibernate.proxy.AbstractLazyInitializer.initia lize(AbstractLazyInitializer.java:53)
    at org.hibernate.proxy.AbstractLazyInitializer.getImp lementation(AbstractLazyInitializer.java:84)
    at org.hibernate.proxy.CGLIBLazyInitializer.intercept (CGLIBLazyInitializer.java:134)
    at com.contentconnections.mpl.publisher.RegistrationC ode$$EnhancerByCGLIB$$4f18b358.toString(<generated >)
    at java.lang.String.valueOf(String.java:2131)
    at java.lang.StringBuffer.append(StringBuffer.java:37 0)
    at org.apache.commons.lang.builder.ToStringStyle.appe ndDetail(ToStringStyle.java:445)
    at org.apache.commons.lang.builder.ToStringStyle.appe ndInternal(ToStringStyle.java:428)
    at org.apache.commons.lang.builder.ToStringStyle.appe nd(ToStringStyle.java:319)
    at org.apache.commons.lang.builder.ToStringBuilder.ap pend(ToStringBuilder.java:825)
    at com.contentconnections.mpl.publisher.Profile.toStr ing(Profile.java:76)
    at java.lang.String.valueOf(String.java:2131)
    at java.lang.StringBuffer.append(StringBuffer.java:37 0)
    at org.apache.commons.lang.builder.ToStringStyle.appe ndDetail(ToStringStyle.java:445)
    at org.apache.commons.lang.builder.ToStringStyle.appe ndInternal(ToStringStyle.java:428)
    at org.apache.commons.lang.builder.ToStringStyle.appe nd(ToStringStyle.java:319)
    at org.apache.commons.lang.builder.ToStringBuilder.ap pend(ToStringBuilder.java:825)
    at com.contentconnections.mpl.publisher.auth.UserBack ingData.toString(UserBackingData.java:77)
    at com.contentconnections.mpl.publisher.auth.User.toS tring(User.java:62)
    at java.lang.String.valueOf(String.java:2131)
    at java.lang.StringBuffer.append(StringBuffer.java:37 0)
    at net.sf.acegisecurity.providers.AbstractAuthenticat ionToken.toString(AbstractAuthenticationToken.java :78)
    at java.lang.String.valueOf(String.java:2131)
    at java.lang.StringBuffer.append(StringBuffer.java:37 0)
    at net.sf.acegisecurity.context.security.SecureContex tImpl.toString(SecureContextImpl.java:70)
    at java.lang.String.valueOf(String.java:2131)
    at java.lang.StringBuffer.append(StringBuffer.java:37 0)
    at net.sf.acegisecurity.context.HttpSessionContextInt egrationFilter.doFilter(HttpSessionContextIntegrat ionFilter.java:160)
    at net.sf.acegisecurity.util.FilterChainProxy$Virtual FilterChain.doFilter(FilterChainProxy.java:303)
    at net.sf.acegisecurity.util.FilterChainProxy.doFilte r(FilterChainProxy.java:173)
    at net.sf.acegisecurity.util.FilterToBeanProxy.doFilt er(FilterToBeanProxy.java:125)
    at org.apache.catalina.core.ApplicationFilterChain.in ternalDoFilter(ApplicationFilterChain.java:186)
    at org.apache.catalina.core.ApplicationFilterChain.do Filter(ApplicationFilterChain.java:157)
    at org.springframework.orm.hibernate3.support.OpenSes sionInViewFilter.doFilterInternal(OpenSessionInVie wFilter.java:172)
    at org.springframework.web.filter.OncePerRequestFilte r.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.in ternalDoFilter(ApplicationFilterChain.java:186)
    at org.apache.catalina.core.ApplicationFilterChain.do Filter(ApplicationFilterChain.java:157)
    at org.apache.catalina.core.StandardWrapperValve.invo ke(StandardWrapperValve.java:214)
    at org.apache.catalina.core.StandardValveContext.invo keNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(S tandardPipeline.java:520)
    at org.apache.catalina.core.StandardContextValve.invo keInternal(StandardContextValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invo ke(StandardContextValve.java:152)
    at org.apache.catalina.core.StandardValveContext.invo keNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(S tandardPipeline.java:520)
    at org.apache.catalina.core.StandardHostValve.invoke( StandardHostValve.java:137)
    at org.apache.catalina.core.StandardValveContext.invo keNext(StandardValveContext.java:104)
    at org.apache.catalina.valves.ErrorReportValve.invoke (ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardValveContext.invo keNext(StandardValveContext.java:102)
    at org.apache.catalina.core.StandardPipeline.invoke(S tandardPipeline.java:520)
    at org.apache.catalina.core.StandardEngineValve.invok e(StandardEngineValve.java:109)
    at org.apache.catalina.core.StandardValveContext.invo keNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(S tandardPipeline.java:520)
    at org.apache.catalina.core.ContainerBase.invoke(Cont ainerBase.java:929)
    at org.apache.coyote.tomcat5.CoyoteAdapter.service(Co yoteAdapter.java:160)
    at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyo teHandler.java:300)
    at org.apache.jk.common.HandlerRequest.invoke(Handler Request.java:374)
    at org.apache.jk.common.ChannelSocket.invoke(ChannelS ocket.java:743)
    at org.apache.jk.common.ChannelSocket.processConnecti on(ChannelSocket.java:675)
    at org.apache.jk.common.SocketConnection.runIt(Channe lSocket.java:866)
    at org.apache.tomcat.util.threads.ThreadPool$ControlR unnable.run(ThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:534)

  • #2
    This is an infamous problem outside of Acegi but with Hibernate. It could have something to do with mod_jk though, because you could be trying to use Hibernate persisted data after the transaction has completed. In short:

    1) Turn on logging for Hibernate.
    2) If using spring to control Hibernate transactions, log that too.
    3) Look to see if a second hibernate session is being opened - this is important.
    4) Look to see when the session is being closed - probably on the transaction bondary. You can't use your hibernate persisted data after that, as configured.
    5) Consider using the spring OpenSessionInViewFilter - before the acegi filters.
    6) Lazy is off by default in 2,x and on by default in 3.x . Try turning it off.
    6) If all else fails, take a look at session.lock(object, LockMode.NONE);

    Of course I haven't mentioned acegi - its doubtful the problem is there but I suppose anything is possible. Unless you have something Hibernate Related in a custom UserDetails object. Like your com.contentconnections.mpl.publisher.RegistrationC ode . Hmm.

    Good luck,
    iksrazal

    Comment


    • #3
      I know it's a common problem when using Hibernate in webapps. That's why I've tried to avoid putting anything loaded from Hibernate into the users servlet session. I am using spring to control Hibernate transactions and am using the OpenSessionInViewFilter.

      It doesn't happen all the time either. It works when the webapp is first deployed and right after you restart the webapp, but after about a day and half of use (via mod_jk) it starts having problems.

      The reason I posted here is because Acegi seems to be trying to load my custom implementation of the UserDetails interface. This occurs even when a user is first visiting the site and only happens when the servlet is connected to via mod_jk. So right now I have users just accessing tomcat directly while we're doing our beta testing and we don't encounter these problems. But I'd like to get them fixed so that I can make the URLs nice and pretty and use Apache to serve static content, etc.

      I was just wondering if anyone else had encountered problems with using Acegi and mod_jk that could be related. I was also wondering if anyone knew of a more developed Hibernate AuthenticationDao. The main reason I decided to use my own was so I could load some custom data and so I could add more features like adding users, changing passwords, etc.

      Thanks again,
      Rich

      [edit]
      Here's a little more info. I looked in the HttpSessionContextIntegrationFilter at where it seems to be having problems. At the beginning of the doFilter() method, this check is performed.

      Code:
              if &#40;&#40;request != null&#41; && &#40;request.getAttribute&#40;FILTER_APPLIED&#41; != null&#41;&#41; &#123;
                  // ensure that filter is only applied once per request
                  chain.doFilter&#40;request, response&#41;;
              &#125; else &#123;
                  if &#40;request != null&#41; &#123;
                      request.setAttribute&#40;FILTER_APPLIED, Boolean.TRUE&#41;;
                  &#125;
      
                  if &#40;ContextHolder.getContext&#40;&#41; != null&#41; &#123;
                      if &#40;logger.isWarnEnabled&#40;&#41;&#41; &#123;
                          logger.warn&#40;
                              "ContextHolder should have been null but contained&#58; '"
                              + ContextHolder.getContext&#40;&#41; + "'; setting to null now"&#41;;
                      &#125;
      
                      ContextHolder.setContext&#40;null&#41;;
                  &#125;
      I've seen this warning in the logs a couple of times before and I'm not sure what it means or how to correct this problem. I think if I could make this warning go away my problem would go away.

      Comment


      • #4
        That looks like 0.8.2 code to me, so please upgrade to 0.8.3 where we finally{} the clean up of ContextHolder. It sounds like your tracing of your problem led to the same error as motivated by 0.8.3, so it makes sense to upgrade and see if the problem disappears.

        Comment


        • #5
          Thanks for the reply Ben. I did a search on the warning and wound up finding the bug posting http://opensource.atlassian.com/proj.../browse/SEC-20. I upgraded to 0.8.3 to see if that would fix it and it's been up and running for 2 days now, a record. Seems to have done the trick. Thanks.

          Comment


          • #6
            I think I found a decent way to work around other lazy initialization exceptions that are related to user data stored in the session. The problem is that I created an extension of the UserDetails interface that adds a profile attribute. The users profile contains collections of data that is lazily loaded. I don't want to have to initialize() the whole object graph because that could become extremely costly on a per http session basis.

            What I plan on doing is to create a servlet filter that will reload the users profile when they come back to the site. So, after the HttpSessionContextIntegrationFilter passes the buck to my new filter it will get the SecureContext and then get the Authentication object. At this point, if the Authentication object is an instance of UsernamePasswordAuthenticationToken I can set the details attribute.

            I think this will work out pretty well in my situation. Does this sound like a good way to make the users profile available to the jsp authors transparently via the extended UserDetails interface no matter how lazily hibernate is loading the object graph? Or is this a half-baked idea that someone can maybe point out the flaws and give me some better ideas?

            I would appreciate any feedback,
            Rich

            Comment


            • #7
              Hi,

              Have you thought about applying a secondary cache to the lazily loaded Collection? That would allow a cache of only the identifiers of each instance, or the objects themselves if the Object containing the Collection is also cached.

              If no, would the acegi 'remember me' services help?

              iksrazal

              Comment


              • #8
                I'm not sure about caching the collection or the object containing the collection. How would that help with the object collection being loaded in a separate session as it's parent?

                I don't think the remember me services would help because it's all in a single user session.

                Comment


                • #9
                  How would that help with the object collection being loaded in a separate session as it's parent?
                  Quoting "Hibernate in action" :

                  "The Hibernate second-level cache has process or cluster scope; all sessions share the same second-level cache. The second-level cache actually has the scope of a SessionFactory."

                  Is that clearer?
                  iksrazal

                  Comment


                  • #10
                    But I'd still have to do some magic to reattach the user data in the http session to the hibernate session, wouldn't I? How would I do that?


                    Right now the approach I'm taking is to have loadUserByUsername() return just a simple UserDetails object minus the Profile data, because in case the http session data is serialized I don't want the whole object graph serialized. Then, after the httpSessionContextIntegrationFilter and the rememberMeProcessingFilter I have a LoadUserDetailsFilter which grabs the username from the authentication token in the SecureContext, looks up the full UserDetails object, creates a new UsernamePasswordAuthenticationToken with the full UserDetails and sets that in the SecureContext. When the filter chain is being exited, it puts the original authentication token back in the SecureContext so that it is what gets put in the session. I may also need to copy the password and authorities over in case they changed.

                    I don't think this is the best solution, but I don't want to have to disassociate the user details and the profile because there are some administrative cases where it's handy to have them together, such as listing users.

                    Comment


                    • #11
                      Alright, I'm hoping that I've found a workaround. It's in the HIbernate reference doc at chapter 11.6. Basically, you can use the session.lock() method to reattach an object to a session.

                      If I do that and then do a refresh on the user profile that should work, I hope.

                      Comment


                      • #12
                        Hi,

                        I think I undertand the problem - I have a custom UserDetails myself but have lazy=false in that particular case.

                        Two things:

                        1) When using a second level cache, you shouldn't need to re-attach the object to the hibernate session, since the object performs lazy operations independant of all hibernate sessions at the SessionFactory level.

                        Why do you think you would need to? In the case of a second level cache, re-attaching the object to the session doesn't buy you anything I'm aware of.

                        2) If indeed you do need to:

                        http://www.hibernate.org/hib_docs/api/net/sf/hibernate/Session.html#lock(java.lang.Object,%20net.sf.hiber nate.LockMode)

                        Obtain the specified lock level upon the given object. This may be used to perform a version check (LockMode.READ), to upgrade to a pessimistic lock (LockMode.UPGRADE), or to simply reassociate a transient instance with a session (LockMode.NONE).
                        The latter would be your case:

                        session.lock(object, LockMode.NONE);

                        I used that trick before I mastered somewhat openSessionInView, when I wanted to use the lazy object after the session was closed.

                        Hope that helps,
                        iksrazal

                        Comment


                        • #13
                          I did not understand the semantics of the 2nd level cache I guess. I didn't know you don't need to reassociate the object with the hibernate session. That's good to know, I'll probably use that in the future. For now, I'm going to try the lock() method of reattaching the UserDetails to the session.

                          The 2nd level cache is probably the better way to solve the problem but I've looked and there doesn't seem to be a quick and dirty howto anywhere. I looked in the hibernate reference docs, "Pro Hibernate 3" and "Hibernate in Action" and none give a quick-and-dirty example of a 2nd level cache configuration. You wouldn't happen to have one would you? Otherwise, I'm going to have to wait until I have more time to research and investigate.

                          Thanks for all the help,
                          Rich

                          Comment

                          Working...
                          X