Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Forcing LWP authentication

by drewbie (Chaplain)
on Oct 20, 2006 at 21:46 UTC ( [id://579712]=perlquestion: print w/replies, xml ) Need Help??

drewbie has asked for the wisdom of the Perl Monks concerning the following question:

I have a module which accesses a web server (RT) via an ATOM-based API. The server (not surprisingly) requires authentication for requests to be processed. BUT, I end up having 2x as many actual HTTP requests because the ATOM client makes the initial request, the server returns 401, the client makes a second request with the credentials, and then finally gets the response.

I'm wondering if there is a way to force LWP to send the Authorization header on the initial request to save the extra round trip. I know it sounds trivial, but a single run of the client can generate 50-100 HTTP requests for data from the server. The client is run hundreds of times per day (creating a new ticket), so those extra requests do add up. Is this possible or am I off my rocker?

Drew

Replies are listed 'Best First'.
Re: Forcing LWP authentication
by brian_d_foy (Abbot) on Oct 21, 2006 at 00:16 UTC

    Send the Authorization header with every request. You don't have to wait for the server to challenge you (and for those of you who think that, recall that HTTP is a stateless protocol). From RFC 2616, Section 14.8 (I added the emphasis):

    A user agent that wishes to authenticate itself with a server--usually, but not necessarily, after receiving a 401 response--does so by including an Authorization request-header field with the request.

    You don't have to force LWP to do it; it sounds like the ATOM client needs to know to do it.

    It's difficult to point to any concrete fixes without code though.

    Update: added the extract from RFC 2616

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
      Thanks for the replies so far. In my case, I'm using RT::Client (not sure if it's on CPAN - I think $work paid Best Practical to write it). It uses a custom LWP UserAgent class so it (hopefully) should be straightforward to add a header on outgoing requests. Now I just need to dive into LWP to figure out how to set headers.
      my $rv = $self->SUPER::new(%args); $rv->ua( LWP::UserAgent::RTClient->new($rv) ); $rv->ua->{keep_alive} = 1; $rv->ua->{requests_redirectable} = [ qw( GET HEAD OPTIONS ) ];
      Thanks,
      Drew
Re: Forcing LWP authentication
by shmem (Chancellor) on Oct 20, 2006 at 23:22 UTC
    As I understand RFC2616 and RFC2617, the client authentication must be challenged by the server - via sending a 401. That makes sense, since the client must not deal out authentication tokens to servers which don't request them. Also, the authentication mechanism supported by the server isn't known beforehand.

    But if you know realm and authentication mechanism, you could try to add an appropriate "Authorization:" header directly to the HTTP::Headers structure of the LWP object; don't know whether that works (i.e. whether LWP ignores that header line on the initial request and behaves standard anyways), but it could be worth a try.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Forcing LWP authentication
by Khen1950fx (Canon) on Oct 20, 2006 at 23:50 UTC
    shmem is right. Client authentication must be challenged by the server. But, and this is a big "but", I think that you can add an appropriate "Authorization:" header using lwp::request. It has the -H option that'll do that, and it has the -f option to force it through---"but" the server might not go for it. Give it a try. See: lwp::request
Re: Forcing LWP authentication
by drewbie (Chaplain) on Oct 23, 2006 at 18:10 UTC
    As a follow up, I did figure out how to send the appropriate headers to RT. However, RT is caching the nonce values (this is WSSE authentication via an ATOM client) so it doesn't matter anyway. :-(

    But for reference in case anyone needs it, here's what I added to RT/Client.pm. X-WSSE and Authentication are definitely required. I couldn't quickly determine if the WWW-Authenticate header is required by the spec so I sent it along anyway (after trying it both ways).

    my ($username, $password) = $ua->get_basic_credentials("Support"); # This code is culled from XML::Atom::Client::munge_request(). my $nonce = XML::Atom::Client::make_nonce(); + my $nonce_enc = encode_base64($nonce, ''); + my $now = DateTime->now->iso8601 . 'Z'; + my $digest = encode_base64(sha1($nonce . $now . ($password || '')), '' +); $ua->default_header('WWW-Authenticate', 'WSSE realm="Support", profile +="UsernameToken"'); + $ua->default_header('Authorization', 'WSSE profile="UsernameToken"'); $ua->default_header('X-WSSE', sprintf + qq(UsernameToken Username="%s", PasswordDigest="%s", +Nonce="%s", Created="%s"), + $username || '', $digest, $nonce_enc, $now);

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://579712]
Approved by Hue-Bond
Front-paged by andyford
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2024-04-20 06:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found