Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Q. Augmenting the RPC data sent from client

    Is there a way to add application-specific HTTP header parameters to the outgoing RPC from the SmartGWT Client?

    I see there is a com.smartgwt.client.rpc.RPCManager class, but no ability to register a callback handler to augment the outgoing HTTP requests.

    The motivation for doing this is to be able to add proprietary fields to the HTTP message which are used by the server for user identification and message integrity checking. When the RPC arrives on the server side a HTTP Servlet Filter examines the request to determine if its authentic and who its from before allowing it to be dispatched to SmartGWT servlet for processing.

    Alternatively, is there a way to add such parameters automatically to every RPC payload?

    Any guidance on how to achieve this would be greatly appreciated. Thx in advance.

    - Brenton

    #2
    You can do this by adding an HTTP parameter to the system-wide default actionURL via RPCManager.setActionURL().

    Comment


      #3
      Looking into this further, adding a URL parameter via setActionURL() may not be sufficient because its not possible to inspect the request payload before its being sent in order to create a hash (signature) of it.

      Ideally, the ability to register a Request filter with RPCManager would be the best approach. Something like the following being added to

      package com.smartgwt.client.rpc;

      interface RPCRequestFilter {
      /**
      * Invoked by RPCManager before request is dispatched.
      */
      RPCRequest filter(RPCRequest request);
      }

      public class RPCManager {
      ...
      /**
      * Registers a filter to receive notification of request dispatch events
      */
      public void registerRequestFilter(RPCRequestFilter filter);
      ...
      }

      Then it would be easy to add the extra data to the Request via:

      package mypackage;

      public class MyRPCRequestFilter implements RPCRequestFilter {

      public RPCRequest filter(RPCRequest request) {
      String payload = request.getDataAsString();
      String signature = hash(payload); // calculate a signature base on payload

      Map customHeaders = new HashMap();
      customHeaders.put("X-ABC-Signature", signature);
      customHeaders.put("X-ABC-AuthToken", MyAuthSystem.getCurrentUsersToken());
      request.setHttpHeaders(customHeaders); // adds custom headers to request
      return request;
      }

      Comment


        #4
        What problem are you trying to solve?

        Cross-domain request spoofing is solved by just including some arbitrary parameter that the server writes out into the containing page. setActionURL() handles this.

        Are you trying to do something further, like have the client system sign requests with a secret value to prevent man-in-the-middle attacks? There is the ability to add some calculated value to all DataSource requests via an override of DataSource.transformRequest(). Most likely, non-DataSource RPCRequests will not need to be signed - anything that needs signing could be done as a DataSource request instead.

        Comment


          #5
          My motivation is three-fold:

          1. Establish the caller's identity. The application is used by many different clients. Although the dataset definitions for all clients are the same, the actual data is different. Therefore each data request needs to include the caller's identity. Admittedly this could be added to the application interfaces but I prefer not polluting those interfaces with ClientID info. I would rather ClientID be treated as a contextual parameter much like Google AppEngine does with namespaces or how Transaction Contexts are propagated implicitly. Hence the desire to add it to the HTTP Header. This also allows the server to determine at the HTTP filter stage of processing whether a HTTP Request should be processed further or not rather than later in the application logic.

          2. Guarantee message integrity. Apart from adding the ClientID to the call, the entire message's payload is signed (i.e. hash( payload + shared secret token + message seq number) to obtain a signature value which is then sent in the HTTP header). . This prevents Man-In-The-Middle type attacks where the message is modified in transit. It also prevents impersonation type attacks where the clientID is known since the secret token is not known (The token is obtained out of band). This signature needs to be added to the message, and again, I prefer to keep it out of the application APIs.

          3. Prevent Replay of requests. Finally, a third HTTP header attribute is added - a message sequence number - to prevent an authentic request from being captured and replayed.

          Part of this application already exists and uses the above design as part of its program to program communication which runs over HTTP. So I was hoping to simply broaden the current security scheme to encompass this new GWT-based part of the app.

          I prefer having these security methods implemented at this level because:
          a) its orthogonal to the application. The security (authenticity and integrity) of the message are really not related to the message's contents as they are to the message as a whole. Therefore, I was hoping to keep such mechanisms out of the application level of the communications protocol (i.e. the dataset layer).
          b) its technology independent. Implementing security at this level isn't tied to JSON or any other RPC / application-level technology. Its implemented at the transport level.
          c) allows the security checks to be implemented in the webserver's HTTP stack (as a Servlet Filter) rather than in the servlet as an application component.
          d) allows for other security mechanisms to be easily added without changes required at the application level. For instance, I can easily add message encryption without even touching the application classes simply by introducing an extra step in the filter() method that encodes the payload (treated as a string) before its dispatched and have a webserver's filter reverse the encoding to recover the payload before allowing the request to proceed on to the servlets.

          This post is getting a bit long, so I won't go into why these security mechanisms were chosen over alternatives such as SSL. If I ever get time after this project I would be happy to write a short tech note about why this approach in this situation is better that the alternatives.

          I know this is a bit of an ask to add new functionality to the core (RPCManager) but it would be extremely helpful for developing secure yet flexible GWT-based clients. I expect others would find such functionality useful for similar reasons.
          Last edited by bcamac; 13 Apr 2011, 21:37.

          Comment


            #6
            We'll go ahead and give you the benefit of the doubt that when people inevitably say "why not use SSL" (which is designed to basically solve this set of problems) you have some very nuanced answer :)

            As previously mentioned, you can achieve all of this using DataSource.transformRequest/transformResponse, which gives you the ability to completely control how the DataSource uses the RPCRequest / RPCManager system to send and receive data. This means that you can create a single, reusable DataSource class for use with any SmartGWT data-aware components, and anything that goes through that DataSource will follow your protocol, without the components or UI code knowing anything about it.

            We understand that your proposed RPCManager-level API would allow deeper orthogonality by allowing various existing DataSource classes to be used in any mix, even allowing developers to override DataSource.transformRequest and be able to use it for application-level purposes while remaining unaware of the encoding going on at the RPCManager level. If this is key for you, we have a Feature Sponsorship program that would allow you to get the feature added to the framework.

            Comment


              #7
              I'll move this thread into Feature Sponsorship as you mentioned.

              Just for the benefit of others, the reason we're not using SSL are for at least the following reasons:
              1. Its a very heavy weight solution that is processor and network intensive. The initial SSL handshake alone adds several round trips to the communications link before its even ready to begin carrying traffic. The protocol we're proposing requires no such warm-up.
              2. The protocol is often blocked in 'guest' networks which limits the locations that clients can connect from. Network admins don't like SSL connections because their packet sniffing IDS systems no longer work on such comms. Our protocol correctly delinates between authentication, authorization, confidentiality and integrity. SSL combines these all together into a take-it-or-leave-it one size fits all. Our protocol allows, for instance, authentication of the end user and message integrity confirmation without requiring message confidentiality (encrypted payload).
              3. If there are any issues with the certificate or root CA (of which there have been a few in recent years) then end users are given very technical pop-up dialogs to complete in order to proceed. Our end-user community is not tech savvy and such dialogs are often dismissed. This goes to the heart of the issue here. We would like to establish an application specific (thus proprietary) secure communications channel between two parts of an application. Its not about establishing trust (a la SSL signing chains) with an unknown service.
              4. SSL doesn't (easily) establish client identity. While it is possible to issue SSL certs that end users can install, the problem is that they need to be installed in the browser. This is very intrusive for most end users - and rightly so.
              5. Its cheaper than buying expensive SSL certificates. Although not a deciding factor, it doesn't hurt :)
              6. Fundamentally, SSL was designed to solve a different set of problems that this particular situation.

              Hence we prefer to go with the transparent, non-intrusive, light-weigh, purpose-built security system I outlined above.

              Transforming the datasource is close to what we want in its genericity but not quite there. We would prefer that any HTTP communication happening from the client automatically be wrapped with this protocol and thus are looking for a hook / interception point just above HTTP send / receive level.

              I'll continue this thread in Isomorphic's Sponsored Feature area.

              Thanks for the quick responses.

              - Brenton
              Last edited by bcamac; 14 Apr 2011, 10:00.

              Comment


                #8
                All very good points.

                Just curious how you have the user input the identity information you use in lieu of a normal certificate. Do you just use ordinary user/pass credentials to encrypt messages, perhaps add in a SecureId token?

                Comment


                  #9
                  Good question. The short answer is: user identity is sent with the GWT-client as an HTML doc parameter: in other words, it exists in the GWT-client's context. The GWT-client reads this at startup. The value of this token is not used for authorization just authentication. Hence its value is not a secret.

                  However, to be able to use it, the GWT-client does need a secret token which it will use to sign the requests. That token is obtained out-of-band via a request to a 3rd party webapp that the user has already logged into (and thus authenticated against using whatever mechanism they choose - username/password, openID, OAuth, etc). The webapp delegates the request for a token to the GWT-server with which it has already established trust. The end result is that the GWT-client obtains a secret token over a connection that the end-user has established and which is out-of-band of the GWT-client / server connection.

                  Thats probably all not very clear, and sounds more complicated than it is. But it is a natural design for this application which operates in the context of an existing 3rd party web-based application. I think I really need to write a paper about how the whole thing hangs together - even if just for documentation / future reference. I would prefer to be able to include specific code snippets in the paper of the various elements of the architecture - Smart GWT client being one of them - to provide concrete explanation. Hence the desire to have the feature added to SmartGWT so the complete solution can be coded before I start writing documentation about it.

                  Comment


                    #10
                    I looked into the recommendation you sighted above (using RPCManager.setActionURL() ), however the documentation says "Note that if you override this global default and your application uses DataSource databound components [which it does otherwise I wouldn't be using SmartGWT], you'll need to dispatch the DataSource requests from your RPC handler. Your other option is to specify a url on a per-request basis."
                    Sounds problematic. In otherwords, this change suddenly requires lots of code changes in my client.

                    I've tried some other experiments, including adding parameters to each DataSource request (not the ideal approach but satisfactory - if it will work). Specifically, I've tried

                    <Datasource>.setDefaultParams(paramsMap);
                    <Datasource>.setProperty("myPropertyName", "myPropertyValue");

                    But when I view the HTTP request sent to the server for the Datasource none of these parameters accompany the HTTP request.

                    How can I set a parameter that is to accompany every Datasource request or better yet every RPC? Ideally, it would be nice to set such a value at a global level rather than on every Datasource instance.

                    Comment


                      #11
                      The docs for setActionURL() are related to replacing the default IDACall servlet with custom server-side code. You really just need to do something like:

                      Code:
                      RPCManager.setActionURL(RPCManager.getActionURL() + "?param=value");
                      That's the only change you'll need to make to incorporate a specific HTTP parameter in all requests.

                      Comment


                        #12
                        com.smartgwt.client.rpc.RPCManager defines setActionURL() but no getActionURL().
                        Last edited by bcamac; 17 Apr 2011, 09:13.

                        Comment


                          #13
                          Originally posted by Isomorphic
                          The docs for setActionURL() are related to replacing the default IDACall servlet with custom server-side code. You really just need to do something like:

                          Code:
                          RPCManager.setActionURL(RPCManager.getActionURL() + "?param=value");
                          That's the only change you'll need to make to incorporate a specific HTTP parameter in all requests.
                          I'm very interested in doing this, but in smartclient, not smartgwt. Is it possible?

                          Comment


                            #14
                            The equivalent SmartClient code is:

                            Code:
                            isc.RPCManager.addClassProperties({ actionURL : [i]newURL[/i] });

                            Comment


                              #15
                              that's what I was doing:
                              http://forums.smartclient.com/showpost.php?p=87069&postcount=9

                              But then the problem depicted in that thread has arisen, actually the url becomes like:
                              /isomorphic/IDACall?locale=it/filename.pdf&isc_rpc=1&isc_v=v8.2p_2012-05-24&isc_tnum=7

                              so, how could I solve that problem? Is it possible to modify the actionURL for every single dsRequest so that I can attach the param in the right format, ie

                              /isomorphic/IDACall/filename.pdf?isc_rpc=1&isc_v=v8.2p_2012-05-24&isc_tnum=7&locale=it

                              Comment

                              Working...
                              X