Loading ...
Sorry, an error occurred while loading the content.

easy way to make custom, derived transport?

Expand Messages
  • Fred Clift
    Hi - I m looking to make a SOAP::Lite client to talk to an existing SOAP service that runs on a custom transport (standard HTTP over a gssapi/kerberos
    Message 1 of 2 , Nov 12, 2002
    • 0 Attachment
      Hi - I'm looking to make a SOAP::Lite client to talk to an existing SOAP
      service that runs on a custom transport (standard HTTP over a
      gssapi/kerberos tunnel). The server and other clients already exist - I'm
      just trying to make a perl client too.

      I have a helper commandline app that reads/writes stdin/out and handles
      all the encryption -- I'd like to take the freshly connected socket,
      fork/exec my program and do some dup-plumbing to make the application talk
      to the helper app and the helper app will speak to the network socket.


      So, I've been digging through SOAP::Lite and it seems that it would take a
      lot of cut-and-paste inheritance to do what I want.

      Something like derive a new class say NLite from Lite, cut and paste a
      bunch of code into an sub new{} that replaces the assignment of _transport
      with a class derived from SOAP::Transport where I would use a class
      derived from SOAP::Transport::HTTP::Client or somethign like that etc etc,
      eventually getting down into LWP::Protocols::http where I would override
      _new_socket, where I could insert a dup/fork/exec bit of code and do what
      I want. The problem I have is that it would end up taking like 6 or 8
      derived classes to get this deep, cut-n-pasting code from the real classes
      to do this. Things like "maintaince nightmare" and "keeping old bugs"
      leap to mind when I think of this.

      So, my question is, is there a way that I can easily supply a custom,
      derived from SOAP::Lite::Transport::HTTP and have SOAP::Lite use it
      without having to modify SOAP::Lite?

      I note that SOAP::Transport::HTTP is a descendednt of LWP::UserAgent, and
      I'd be happy to supply my own derived LWP::UserAgent to use in place of
      this one if I could...

      Ideas? Comments?

      Any help you can give me would be appreciated.

      Fred

      --
      Fred Clift - fclift@... -- Remember: If brute
      force doesn't work, you're just not using enough.
    • Fred Clift
      All: A week ago or so, I aksed if there were an easy way to fiddle around with the low-level transport of SOAP::Lite - I wanted to do tunneled
      Message 2 of 2 , Nov 20, 2002
      • 0 Attachment
        All:

        A week ago or so, I aksed if there were an easy way to fiddle around with
        the low-level transport of SOAP::Lite - I wanted to do tunneled
        SOAP::Transport::HTTP stuff -- basically normal http transport with a
        custom encryption wrapper around it. I _didn't_ want to have to derive my
        own classes and cut and past a lot of code, or edit SOAP::Lite or anything
        so I started playing around with symbol table hacking...

        I have a command-line program that you pass as command line arguments the
        file descriptors to read/write from and it takes care of the
        encryption/decryption so I basically wanted to dup2 the raw network socket
        to make it talk to a fork/exec'd program instead of the 'real' connection.
        (Incidentally, gssapi encryption with kerberos 5 is what I'm working on
        here...)

        Sample code for doing this is show below, (slightly edited). It is NOT
        thread-safe - it is ugly - it works. to use, set some params
        (vroot_*) call gssSOAPSetup(), make your soap calls, which, in the process
        of getting a socket, get some magic done to the socket to add encryption,
        and then when done call the gssSOAPRestore.


        I've seen several requests in the week I've been on the list to do custome
        things with some of the lower-level base classes used by http-transported
        SOAP::Lite and the same technique can be used for them: find a part of the
        code base code that has access to the data you want, and temporarily
        substitute your own function in place of it - your code could do something
        as simple as define a new class/package variable, and stash data in it
        when the function is called -- ie someone wanted the server headears or
        the remote IP that got connected to -- somewhere in LWP::UserAgent, you
        can poke in a function that stores a copy of this data, and then calls the
        'stock' function so that you can inspect it later...

        At any rate, this has been one big learning experience in object-oriented
        perl for me (read that as "I have much less hair -- I've pulled it all
        out").

        I hope this sample code can get future folks on the ?right? path to do
        this type of thing.

        Mr Kulchenko, you've done a fine job with SOAP::Lite - thanks. (you
        mentioned refactoring the package - perhaps allow a user to pass in a
        derived LWP::UserAgent for use in making the connection? - you probalby
        already can and I'm just unobservant :).

        Again, thanks.

        Fred Clift

        ------------------------------------------------------------------------
        package gssSoap;
        use strict;
        use SOAP::Lite;
        use LWP::Protocol::http;


        our ($vroot_save, $vroot_service, $vroot_keytab, $vroot_timeout)
        $vroot_save = \&LWP::Protocol::http::_new_socket;
        #encryption alg parameters
        $vroot_errfile, $vroot_gsspipe);
        $vroot_service = '';
        $vroot_keytab = "";
        $vroot_timeout = 30;
        $vroot_errfile = "/dev/null";
        $vroot_gsspipe = "./gsspipe";

        #substitute my wrapped socket open call
        sub gssSOAPSetup {

        local $^W;
        *LWP::Protocol::http::_new_socket = \&my_new_socket;
        }

        #put the original one back
        sub gssSOAPRestore {
        local $^W;
        *LWP::Protocol::http::_new_socket = \&$vroot_save;
        }


        # replaces LWP::Protocol::http::_new_socket - calls the normal one and
        then inserts
        # gsspipe in between
        sub my_new_socket {
        use Socket qw(AF_UNIX SOCK_STREAM PF_UNSPEC AF_INET);
        use POSIX;

        # call orig function
        my $sock = &$vroot_save(@_);
        return undef unless $sock;

        #now wedge a shim in between socket and me to handle encryption

        # make sure my socketpair is not close-on-exec
        my $f = $^F;
        $^F = 999999;

        my $newfd = POSIX::dup(fileno($sock));

        my ($pfd, $cfd);
        socketpair($cfd, $pfd, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
        or return undef;
        $pfd->autoflush(1);
        $cfd->autoflush(1);

        my $pid = fork;
        if (!defined($pid)) { return undef;}
        if ($pid == 0) {
        close $cfd;
        my $err;
        open $err, ">$vroot_errfile";
        my @myargs = ($vroot_gsspipe, "-m", "0", "-g", $vroot_service,
        "-s", $newfd , "-t", fileno($pfd) ,
        "-T", $vroot_timeout, "-u", fileno($err));
        if (length($vroot_keytab) > 0)
        {
        @myargs = (@myargs, "-k", $vroot_keytab);
        }
        exec @myargs;
        }

        close $pfd;
        POSIX::dup2(fileno($cfd), fileno($sock));
        $^F = $f;
        return $sock


        };


        1;
        ----------------------------------------------------------------------------------------------------

        --
        Fred Clift - fclift@... -- Remember: If brute
        force doesn't work, you're just not using enough.
      Your message has been successfully submitted and would be delivered to recipients shortly.