Shiro
  1. Shiro
  2. SHIRO-323

DelegatingSubject class cannot be serialized.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.1.0
    • Fix Version/s: 1.2.0
    • Component/s: Subject
    • Labels:
    • Environment:
      Linux

      Description

      I am attempting to send a instance of DelegatingSubject over a JMS topic via serialization, however when I send the object through JMS I get this Exception

      java.lang.RuntimeException: org.apache.shiro.subject.support.DelegatingSubject$StoppingAwareProxiedSession
      at org.apache.activemq.command.ActiveMQObjectMessage.storeContent(ActiveMQObjectMessage.java:111) ~[activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.command.ActiveMQObjectMessage.setObject(ActiveMQObjectMessage.java:162) ~[activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at com.xmlnamespace.panel.server.core.communication.event.EventManager.doSendMessage(EventManager.java:233) ~[com.xmlnamespace.panel.server.core/:na]
      at com.xmlnamespace.panel.server.core.communication.event.EventManager.sendMessage(EventManager.java:208) ~[com.xmlnamespace.panel.server.core/:na]
      at com.xmlnamespace.panel.server.core.communication.mtl.ModelDispatcher.add(ModelDispatcher.java:122) ~[com.xmlnamespace.panel.server.core/:na]
      at com.xmlnamespace.panel.server.core.communication.mtl.ModelDispatcher.collectionChange(ModelDispatcher.java:181) ~[com.xmlnamespace.panel.server.core/:na]
      at com.xmlnamespace.panel.core.shared.communication.mtl.api.CollectionChangeSupport.doFireCollectionChange(CollectionChangeSupport.java:182) ~[shared-objects.jar:na]
      at com.xmlnamespace.panel.core.shared.communication.mtl.api.CollectionChangeSupport.fireCollectionChange(CollectionChangeSupport.java:47) ~[shared-objects.jar:na]
      at com.xmlnamespace.panel.core.shared.user.model.internal.UserModelImpl.addUserLogin(UserModelImpl.java:96) ~[shared-objects.jar:na]
      at com.xmlnamespace.panel.server.core.login.LoginManager.authenticateConnection(LoginManager.java:1013) ~[com.xmlnamespace.panel.server.core/:na]
      at com.xmlnamespace.panel.server.core.communication.broker.BrokerAuthenticationFilter.addConnection(BrokerAuthenticationFilter.java:69) ~[com.xmlnamespace.panel.server.core/:na]
      at org.apache.activemq.broker.MutableBrokerFilter.addConnection(MutableBrokerFilter.java:91) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.broker.TransportConnection.processAddConnection(TransportConnection.java:705) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.broker.jmx.ManagedTransportConnection.processAddConnection(ManagedTransportConnection.java:83) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.command.ConnectionInfo.visit(ConnectionInfo.java:139) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.broker.TransportConnection.service(TransportConnection.java:316) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.broker.TransportConnection$1.onCommand(TransportConnection.java:180) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.TransportFilter.onCommand(TransportFilter.java:69) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.WireFormatNegotiator.onCommand(WireFormatNegotiator.java:113) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.InactivityMonitor.onCommand(InactivityMonitor.java:227) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.TransportSupport.doConsume(TransportSupport.java:83) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.tcp.SslTransport.doConsume(SslTransport.java:91) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:217) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:199) [activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      at java.lang.Thread.run(Thread.java:662) [na:1.6.0_26]
      Caused by: java.io.NotSerializableException: org.apache.shiro.subject.support.DelegatingSubject$StoppingAwareProxiedSession
      at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158) ~[na:1.6.0_26]
      at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330) ~[na:1.6.0_26]
      at org.apache.activemq.command.ActiveMQObjectMessage.storeContent(ActiveMQObjectMessage.java:105) ~[activemq-all-5.6-SNAPSHOT.jar:5.6-SNAPSHOT]
      ... 24 common frames omitted

      I assume that DelegatingSubject is meant to be serialized since it does implement serializable. I noticed that the class inner class StoppingAwareProxiedSession is the culprit. Would the issue be resolved by simply making the Session interface, ProxiedSession class, and StoppingAwareProxiedSession serializable?

        Activity

        Hide
        Les Hazlewood added a comment -

        Hi Michael,

        I'm not sure if the DelegatingSubject should be serializable: the implementation always needs a SecurityManager to function, and a SecurityManager instance is not serializable. If a DelegatingSubject instance was passed across the wire, something would need to acquire the local SecurityManager, associate it with the de-serialized DelegatingSubject, and then bind it to the thread for duration of the invocation.

        Did you get this working in your JMS environment? If so, how? Did you use the Subject.Builder to recreate the Subject on the receiving side?

        Thanks,

        Les

        Show
        Les Hazlewood added a comment - Hi Michael, I'm not sure if the DelegatingSubject should be serializable: the implementation always needs a SecurityManager to function, and a SecurityManager instance is not serializable. If a DelegatingSubject instance was passed across the wire, something would need to acquire the local SecurityManager, associate it with the de-serialized DelegatingSubject, and then bind it to the thread for duration of the invocation. Did you get this working in your JMS environment? If so, how? Did you use the Subject.Builder to recreate the Subject on the receiving side? Thanks, Les
        Hide
        Michael Yara added a comment -

        Les,

        I never actually got this part working since this piece got placed on the back burner of our current project.

        Here are some details on what we currently have and what we are trying to accomplish:

        • Our system is a client server system utilizing JMS for communication.
        • User authentication is preformed via the JMS Broker utilizing a custom authentication plugin so when the clients authenticate they are actually authenticating with the broker.
        • The Broker plugin intercepts the authentication request and passes it off to a custom class that utilizes Shiro to perform the final authentication and reports the authentication status to the broker plugin.
        • The server side holds a model of the currently logged in users utilizing the created Shiro objects.
        • We have developed a proprietary one way persistence framework to persist models between the server and the client. This framework utilizes serialization with Java reflection over JMS.
        • Our goal is to persist the user model to the client in order for the client to determine it's permissions/authorization client side for specific actions without having to send messages back to the server for authorization of these actions.

        I believe i was planning on creating another client side instance of the SecurityManager.
        I am not using the Subject.Builder to make the subjects. i am using the org.apache.shiro.subject.support.DelegatingSubject.DelegatingSubject(SecurityManager securityManager) constructor.

        I am very new to Shiro so I may be taking the completely wrong path and I understand that this is a very unique implementation and not exactly a standard. Any advice on this would be helpful.

        Show
        Michael Yara added a comment - Les, I never actually got this part working since this piece got placed on the back burner of our current project. Here are some details on what we currently have and what we are trying to accomplish: Our system is a client server system utilizing JMS for communication. User authentication is preformed via the JMS Broker utilizing a custom authentication plugin so when the clients authenticate they are actually authenticating with the broker. The Broker plugin intercepts the authentication request and passes it off to a custom class that utilizes Shiro to perform the final authentication and reports the authentication status to the broker plugin. The server side holds a model of the currently logged in users utilizing the created Shiro objects. We have developed a proprietary one way persistence framework to persist models between the server and the client. This framework utilizes serialization with Java reflection over JMS. Our goal is to persist the user model to the client in order for the client to determine it's permissions/authorization client side for specific actions without having to send messages back to the server for authorization of these actions. I believe i was planning on creating another client side instance of the SecurityManager. I am not using the Subject.Builder to make the subjects. i am using the org.apache.shiro.subject.support.DelegatingSubject.DelegatingSubject(SecurityManager securityManager) constructor. I am very new to Shiro so I may be taking the completely wrong path and I understand that this is a very unique implementation and not exactly a standard. Any advice on this would be helpful.
        Hide
        Les Hazlewood added a comment -

        Hi Michael,

        The DelegatingSubject is an implementation class typically not exposed to Shiro API end-users. Probably the best way to solve your problem is the following:

        When sending a message, attach to the message (e.g. as a header, or part of the payload) the information Shiro needs to re-create the Subject instance on the message consumer side. Typically this will be subject.getPrincipals(), the authentication state (i.e. subject.isAuthenticated()) and the host (subject.getHost()). I wouldn't send the session across the wire as that would imply a lot of plumbing to get that to work correctly as well as potential performance issues if the Session is large.

        The message consumer side retrieves the information attached to the message and uses the Subject.Builder to re-create the Subject instance on that side of the wire. Once re-created, bind the Subject to the thread if you want SecurityUtils.getSubject() to work during the message processing thread (most people use subject.execute() to do this automatically - see Shiro's Subject documentation and 'Thread Association': http://shiro.apache.org/subject.html.

        And yes, I would have two Shiro SecurityManager instances - one on the message producer side, the other on the message consumer side. You will need a SecurityManager to use the Subject.Builder correctly.

        Now, given this result, perhaps the resolution to this issue should be that DelegatingSubject should not implement serializable?

        Show
        Les Hazlewood added a comment - Hi Michael, The DelegatingSubject is an implementation class typically not exposed to Shiro API end-users. Probably the best way to solve your problem is the following: When sending a message, attach to the message (e.g. as a header, or part of the payload) the information Shiro needs to re-create the Subject instance on the message consumer side. Typically this will be subject.getPrincipals(), the authentication state (i.e. subject.isAuthenticated()) and the host (subject.getHost()). I wouldn't send the session across the wire as that would imply a lot of plumbing to get that to work correctly as well as potential performance issues if the Session is large. The message consumer side retrieves the information attached to the message and uses the Subject.Builder to re-create the Subject instance on that side of the wire. Once re-created, bind the Subject to the thread if you want SecurityUtils.getSubject() to work during the message processing thread (most people use subject.execute() to do this automatically - see Shiro's Subject documentation and 'Thread Association': http://shiro.apache.org/subject.html . And yes, I would have two Shiro SecurityManager instances - one on the message producer side, the other on the message consumer side. You will need a SecurityManager to use the Subject.Builder correctly. Now, given this result, perhaps the resolution to this issue should be that DelegatingSubject should not implement serializable?
        Hide
        Les Hazlewood added a comment -

        P.S. Can we please keep architectural discussions and associated help on the user list? These types of discussions in a Jira issue are hard to grok for the development team. Thanks!

        Show
        Les Hazlewood added a comment - P.S. Can we please keep architectural discussions and associated help on the user list? These types of discussions in a Jira issue are hard to grok for the development team. Thanks!
        Hide
        Les Hazlewood added a comment -

        I removed Serializable from the implements clause. DelegatingSubject was never really intended to function automatically across VM boundaries. The Subject.Builder should be used to reconstitute Subject instances across VM boundaries.

        Show
        Les Hazlewood added a comment - I removed Serializable from the implements clause. DelegatingSubject was never really intended to function automatically across VM boundaries. The Subject.Builder should be used to reconstitute Subject instances across VM boundaries.
        Hide
        Les Hazlewood added a comment -

        Closing with the 1.2.0 release.

        Show
        Les Hazlewood added a comment - Closing with the 1.2.0 release.

          People

          • Assignee:
            Les Hazlewood
            Reporter:
            Michael Yara
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development