You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by Adrian Sutton <ad...@ephox.com> on 2003/02/27 01:00:43 UTC

RE: Using httpclient on the server to intercept and modify HTTP r esponse

Hi Chris,
HttpClient should be able to do everything you need it to, but you have hit
on one limitation that I've been meaning to fix for a long time now.
There's ways around it and if you pester me enough I might finally get
around to implementing it properly. :)  More below.

>1./ when connecting to something with the HTTPClient API, how do I
determine
>dynamically which type of credentials I should use, if any?

You can always use NTCredentials as they extend UsernamePasswordCredentials,
this is the approach I take.  There is a definitely limitation in HttpClient
that it doesn't tell you what credentials it needs.  This is part 1 of the
stuff I've been meaning to do.  It should give you the Class for the
credentials type and there should be some way of knowing what parameters it
needs as well.

>2./ given that I'm forwarding requests from many clients via one host, are
>there any problems or pitfalls with multiple connections from that host
>using different credentials for each client?  is there any caching for
>example that might mean that the first NT login is used for some/all
>subsequent requests that should in fact be using the credentials for a
>different client?

That depends.  Credentials are stored per realm and are cached in the
HttpState instance for each HttpClient.  For NTLM, the domain name of the
server is used as the realm.  So if you have two users with different
credentials who attempt to access the same NTLM server, the credentials will
get mixed up.  You can (and should) however create a separate HttpState for
each client so that the credentials don't get mixed up too much and this
will also prevent cookies getting mixed up and a bunch of other stuff.

Laura has requested a version of executeMethod() in HttpClient that accepts
a specific state to use and that definitely seems like a good idea -
currently she is using the HttpMethod's directly and not using the
HttpClient class itself.  We'd like everyone to use the HttpClient class as
it makes development easier so I'm hoping that someone (possibly myself)
will look into the possibility of implementing that for 2.0.  It depends on
how complex it is though.

>3./ as I'll need to ask the client to provide credentials, I can either use
>a form or a BASIC authentification request.  If I limit the request to
>"username" and "password" fields, can I safely request that the client's
>username contains "DOMAIN\username" (and then decode it), as I'm not clear
>about where I should obtain domain names for?

You could take that approach, or you could use the nasty hack below to
detect if you're authenticating to NTLM or not and add a specific domain
field to your auth dialog/form.

The nasty hack to find out the realm to authenticate against and whether or
not you need a domain involves:
 	.....
	  // If you might have to authenticate with proxies, don't forget to
check the
	  // Proxy-Authenticate header as well.
        String realm = get.getResponseHeader("WWW-Authenticate").getValue();
        boolean isNTLM = (realm != null &&
realm.toLowerCase().indexOf("ntlm") >= 0);
        String tmpRealm;
        if (isNTLM) {
            if (proxy) {
                tmpRealm = client.getProxyHost();
            } else {
                tmpRealm = src.getHost();
            }
        } else {
            tmpRealm = parseRealmFromChallenge(realm);
        }
	  // isNTLM now stores whether or not you need to get a domain from
the user as well.
	  // tmpRealm now contains the name of the realm you're
authenticating against.
	....


    // Blantantly ripped from HttpClient's Authenticator.java  You may want
to check for updates.
    private String parseRealmFromChallenge(String challenge) {
        log.trace("enter parseRealmFromChallenge(String challenge)");
        try {
            StringTokenizer strtok = new StringTokenizer(challenge, "=");
            String realm = strtok.nextToken().trim();
            int firstq = realm.indexOf('"');
            int lastq = realm.lastIndexOf('"');

            if ((firstq + 1) < lastq) {
                realm = realm.substring(firstq + 1, lastq);
            }

            return realm;
        } catch (Exception ex) {
            System.err.println("Failed to parse realm: " + challenge + " - "
+ ex.getMessage());
            return null;
        }
    }

Hope that helps....

Adrian Sutton, Software Engineer
Ephox Corporation
www.ephox.com


Using appropriate credentials and state with multiple hosts

Posted by Chris Brown <br...@reflexe.fr>.
Hi,

I'm using HttpClient 2.0 alpha 3, and am trying to find out how to work with
multiple hosts, sometimes with authentification, sometimes without,
sometimes with NTLM.  Some questions, hope should be easy to answer...

1.) Is there already some method to parse authentification headers to
extract the realm, or do I have to parse this myself (I've looked around a
bit, may have missed it) ?

2.) Do I need a separate HttpState per client per host?  From the javadocs,
it seems that if more than one host uses the same realm name, such as
"Private" (by coincidence), then I'm stuck, as HttpState can only store one
set of credentials for a given name...

Thanks,
Chris



Re: Using httpclient on the server to intercept and modify HTTP response

Posted by Chris Brown <br...@reflexe.fr>.
Hi Adrian,

Thank you for your detailed answer.  I'd just like to check that I've
understood okay, and ask one more favour (!):

1./ I can't determine what type of credentials I should use directly with
the HttpClient API.  I need to look at HTTP response headers and determine
that myself.  This leads onto another question... what headers are returned
by an NTLM-protected server to indicate that I need to authenticate with
NTLM -- so that I know what to "sniff" for, and what response does it
xpect  -- out of interest (I'd like a short example)?

2./ I should be using one instance of HttpClient per connected user, so that
I can reflect correctly the credentials for the end user (stored in the
state of the HttpClient).  In practice, I could store one instance of
HttpClient in the session attributes of the servlet context for the webapp
of the highlighting service.

3./ thanks for the example. it does help!

Sorry to ask such questions.  I don't have an NTLM test environment, so it's
fun trying to develop support for it..!!  Thanks for the help so far anyway!

- Chris

PS: re: the "limitation"... pester, pester, I'd be happy if it were fixed!
:)



----- Original Message -----
From: "Adrian Sutton" <ad...@ephox.com>
To: "'Commons HttpClient Project'"
<co...@jakarta.apache.org>
Sent: Thursday, February 27, 2003 1:00 AM
Subject: RE: Using httpclient on the server to intercept and modify HTTP
response


> Hi Chris,
> HttpClient should be able to do everything you need it to, but you have
hit
> on one limitation that I've been meaning to fix for a long time now.
> There's ways around it and if you pester me enough I might finally get
> around to implementing it properly. :)  More below.
>
> >1./ when connecting to something with the HTTPClient API, how do I
> determine
> >dynamically which type of credentials I should use, if any?
>
> You can always use NTCredentials as they extend
UsernamePasswordCredentials,
> this is the approach I take.  There is a definitely limitation in
HttpClient
> that it doesn't tell you what credentials it needs.  This is part 1 of the
> stuff I've been meaning to do.  It should give you the Class for the
> credentials type and there should be some way of knowing what parameters
it
> needs as well.
>
> >2./ given that I'm forwarding requests from many clients via one host,
are
> >there any problems or pitfalls with multiple connections from that host
> >using different credentials for each client?  is there any caching for
> >example that might mean that the first NT login is used for some/all
> >subsequent requests that should in fact be using the credentials for a
> >different client?
>
> That depends.  Credentials are stored per realm and are cached in the
> HttpState instance for each HttpClient.  For NTLM, the domain name of the
> server is used as the realm.  So if you have two users with different
> credentials who attempt to access the same NTLM server, the credentials
will
> get mixed up.  You can (and should) however create a separate HttpState
for
> each client so that the credentials don't get mixed up too much and this
> will also prevent cookies getting mixed up and a bunch of other stuff.
>
> Laura has requested a version of executeMethod() in HttpClient that
accepts
> a specific state to use and that definitely seems like a good idea -
> currently she is using the HttpMethod's directly and not using the
> HttpClient class itself.  We'd like everyone to use the HttpClient class
as
> it makes development easier so I'm hoping that someone (possibly myself)
> will look into the possibility of implementing that for 2.0.  It depends
on
> how complex it is though.
>
> >3./ as I'll need to ask the client to provide credentials, I can either
use
> >a form or a BASIC authentification request.  If I limit the request to
> >"username" and "password" fields, can I safely request that the client's
> >username contains "DOMAIN\username" (and then decode it), as I'm not
clear
> >about where I should obtain domain names for?
>
> You could take that approach, or you could use the nasty hack below to
> detect if you're authenticating to NTLM or not and add a specific domain
> field to your auth dialog/form.
>
> The nasty hack to find out the realm to authenticate against and whether
or
> not you need a domain involves:
>   .....
>   // If you might have to authenticate with proxies, don't forget to
> check the
>   // Proxy-Authenticate header as well.
>         String realm =
get.getResponseHeader("WWW-Authenticate").getValue();
>         boolean isNTLM = (realm != null &&
> realm.toLowerCase().indexOf("ntlm") >= 0);
>         String tmpRealm;
>         if (isNTLM) {
>             if (proxy) {
>                 tmpRealm = client.getProxyHost();
>             } else {
>                 tmpRealm = src.getHost();
>             }
>         } else {
>             tmpRealm = parseRealmFromChallenge(realm);
>         }
>   // isNTLM now stores whether or not you need to get a domain from
> the user as well.
>   // tmpRealm now contains the name of the realm you're
> authenticating against.
> ....
>
>
>     // Blantantly ripped from HttpClient's Authenticator.java  You may
want
> to check for updates.
>     private String parseRealmFromChallenge(String challenge) {
>         log.trace("enter parseRealmFromChallenge(String challenge)");
>         try {
>             StringTokenizer strtok = new StringTokenizer(challenge, "=");
>             String realm = strtok.nextToken().trim();
>             int firstq = realm.indexOf('"');
>             int lastq = realm.lastIndexOf('"');
>
>             if ((firstq + 1) < lastq) {
>                 realm = realm.substring(firstq + 1, lastq);
>             }
>
>             return realm;
>         } catch (Exception ex) {
>             System.err.println("Failed to parse realm: " + challenge + " -
"
> + ex.getMessage());
>             return null;
>         }
>     }
>
> Hope that helps....
>
> Adrian Sutton, Software Engineer
> Ephox Corporation
> www.ephox.com
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
commons-httpclient-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail:
commons-httpclient-dev-help@jakarta.apache.org
>
>
>