12 Replies Latest reply on Jan 17, 2007 1:40 AM by ron_sigal

    Detached invokers are too detached from the transport

    starksm64

      So in looking at a request to be able to use the ssl client cert as the caller identity for an ejb as can be done for CLIENT_CERT authentication in the web tier, the current detached invoker framework is too detached from the transport to be able to do this.

      For the JRMP implementation I have no access to the underlying socket (at least that I have been able to find via standard interfaces), and thus have no ability to interact with the ssl session to obtain the session id, client cert, etc.

      I have modified our pooled invoker to add the ssl session id to each invocation because there we do have access to the socket. A custom ssl client/server socket factory provide a mapping between the session id and the ssl certs, and a server side interceptor would have to pick this up as the caller identity for authentication via the JAAS layer.

      The general issue is that there needs to be some hook for transport metadata to be added to the invocation payload. Once I complete the pooled invoker changes and add a testcase I need this ported to the remoting framework as an ejb3 testcase to validate we can support this.

      More generally do we have a hook for being able to push transport metadata to the message invocation payload?

        • 1. Re: Detached invokers are too detached from the transport

          Could use custom marshaller to put extra information into the invocation payload (which is basically what the InvocationUnMarshaller does). However, in this particular case, it won't work because the marshaller/unmarshaller are only passed the stream and not the actual transport object itself. So need to get the info from the SSLSocket, which is not accessible within the unmarshaller.

          I've created jira issue for this in remoting (JBREM-298)

          • 2. Re: Detached invokers are too detached from the transport
            starksm64

            See the updated PooledInvoker changes in 4.0/head and the associated org.jboss.test.pooled.test.SSLSocketsUnitTestCase. We need a similar test based on the remoting framework.

            I'm not happy with coupling between the ssl socket factory, javax.net.ssl.HandshakeCompletedListener, and the proxy layer. How this ties into the jsr-196 authentication api is also a question that needs to be answered when we look at this in the context of how this is done in the remoting framework.

            • 3. Re: Detached invokers are too detached from the transport

              Have added support for adding a HandshakeCompletedListener to the remoting code, so can now get callback when ssl session handshake finished (per JBREM-314).

              Still need to add support at the invocation layer (per JBREM-298). However, am not sure how (or even if) this should really be done. Ideally, would like this behavior to be introduced via an interceptor that the user could add. Only problem is that the ejb invoker does not expose a way to do this currently. Any ideas on a generic way to do this?

              • 4. Re: Detached invokers are too detached from the transport
                starksm64

                The ssl example illustrates the characteristics that have to be supported.

                1. A transport specific socket factory/socket expose context that needs to be integrated
                2. These can be used to associate transport level info with the invocation for use elsewhere.

                So integration with the transport factory and access to the transport "socket" via a low level interceptor are what is required. What exists today?

                • 5. Re: Detached invokers are too detached from the transport

                  As of JBossRemoting 2.0.0 (scheduled for release later this month) and already in CVS HEAD, can add a HandshakeCompletedListener via the following code:

                   Map config = new HashMap();
                   config.put(Client.HANDSHAKE_COMPLETED_LISTENER, myHandshakeListener);
                  
                   InvokerLocator locator = new InvokerLocator(getTransport() + "://" + host + ":" + port);
                   client = new Client(locator, "mock", config);
                   client.connect();
                  


                  Upon the client.connect(), myHandshakeListener will get the callback. The question is how to expose this generically at the ejb level? Should just look in the Invocation object for an entry with a key being the same as Client.HANDSHAKE_COMPLETED_LISTENER (or something similar) and then add it to the config map passed to the remoting Client constructor?

                  Just wasn't sure why we would want to hardcode setting the ssl session id in they invocation payload getting sent over the wire verses having a user create an interceptor to do this? Is the use case for this based on user request or something covered under a spec?

                  • 6. Re: Detached invokers are too detached from the transport
                    starksm64

                    The generic exposure at the invocation context level is some security or transport related aspect concern. What matters is can this be integrated into the client/server handlers of the remoting layer. If I'm paranoid I have to be able to get the socket and get the cert from it and validate any existing invocation content before letting this get outside of the transport layer where I have no ability to assert that the request came over a channel that was encrypted and authenticated as expected.

                    This scenario is outside of the remoting layer, but requires configuration of the aspects involved in the ejb proxy.

                    • 7. Re: Detached invokers are too detached from the transport

                      Well, remoting is not going to provide direct access to the socket itself without writing providing a custom implementation of the socket wrapper class and setting it via config (i.e. using clientSocketClass config property). However, if user does provide a HandshakeCompletedListener to remoting client, as stated above, they will then be able to prevent the client from making a call on the socket associated with the handshake callback (by just thowing an exception out of the handshakeCompleted() method). How/why they would do this, I don't care (or need to)... just want to allow them the ability to do this.

                      So, I think remoting is in good shape in regards to the behavior needed. Now need to know how to integrate this higher up the stack (like in ejb invocation) or if this is even something I need to be responsible for?



                      • 8. Re: Detached invokers are too detached from the transport
                        starksm64

                        I need to see an example of where one can insert a custom interceptor/handler/aspect into both the client and server side if the transport layer to introduce transport specific into into the invocation. A simpler example than ssl certs would be the client local inet address which is inserted into the invocation being validated by the server side. Can you create a testcase for this?

                        • 9. Re: Detached invokers are too detached from the transport
                          anil.saldhana

                          In the long run, I am wondering, will we have testcases to validate binary security tokens on the server side with client side population? The binary tokens include x509 certificates, kerberos tickets, xml tokens(some forms) etc.

                          • 10. Re: Detached invokers are too detached from the transport
                            ron_sigal

                            How about a generalization of HandshakeCompletedListener:

                             interface SocketCreatedListener
                             {
                             void socketCreated(Socket socket);
                             }
                            


                            An instance of SocketCreatedListener could be passed in on the client side:

                             SocketCreatedListener listener = ... ;
                             HashMap config = new HashMap();
                             config.put(Remoting.SOCKET_CREATED_LISTENER, listener);
                             Client client = new Client(locator, config);
                            


                            and on the server side:

                             SocketCreatedListener listener = ... ;
                             HashMap config = new HashMap();
                             config.put(Remoting.SOCKET_CREATED_LISTENER, listener);
                             Connector = new Connector(locator, config);
                            


                            The client and server invokers would be responsible for calling the listener whenever they create a socket. A customized SocketFactory would probably be necessary for some of the less transparent transports.

                            • 11. Re: Detached invokers are too detached from the transport
                              starksm64

                              That sounds fine.

                              • 12. Re: Detached invokers are too detached from the transport
                                ron_sigal

                                I have implemented a version of the solution I suggested above and checked it in to the Remoting HEAD and remoting_2_x branches.

                                1. There are a couple of changes. First, the listener interface, org.jboss.remoting.socketfactory.SocketCreationListener, is

                                public interface SocketCreationListener
                                {
                                 /**
                                 * Called when a socket has been created.
                                 *
                                 * @param socket socket that has been created
                                 * @param source SocketFactory or ServerSocket that created the socket
                                 * @throws IOException
                                 */
                                 void socketCreated(Socket socket, Object source) throws IOException;
                                }
                                


                                and there are two distinct configuration keys for incorporating listeners into socket factories and server sockets:

                                org.jboss.Remoting.SOCKET_CREATION_CLIENT_LISTENER (with value "socketCreationClientListener")

                                and

                                org.jboss.Remoting.SOCKET_CREATION_SERVER_LISTENER (with value "socketCreationServerListener")

                                The reason for distinguishing these is that the same configuration Map can get passed to both a server and a client. For example, it could be passed to a Connector and then later to a Client used by the Connector to push callbacks. Finally, to support configuration by InvokerLocator or xml, the value of the listener parameter can be the name of a class that implements SocketCreationListener and has a default constructor.

                                2. The solution works for the following transports: bisocket, sslbisocket, https, multiplex, sslmultiplex, rmi, sslrmi, socket, and sslsocket. It does not work for the http transport and for the server side of the servlet transport. The reason it doesn't work for http is that HttpURLConnection does not expose its socket factory (though HttpsURLConnection does). It should be possible to write a custom http protocol handler for this purpose, but I won't unless is there is a specific request. And invocations with the servlet transport go through a servlet container, which is outside the scope of Remoting.

                                3. The implementation is based on the classes: CreationListenerSocketFactory, CreationListenerServerSocketFactory, and
                                CreationListenerServerSocket in the package org.jboss.remoting.socketfactory. CreationListenerSocketFactory wraps the SocketFactory that would otherwise be used, and calls the listener whenever a socket is created. CreationListenerServerSocketFactory wraps the ServerSocketFactory that would otherwise be used, and whenever a ServerSocket is created, it wraps that ServerSocket in a CreationListenerServerSocket, which calls the listener whenever it creates a socket.