cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Glynn, Eoghan" <eoghan.gl...@iona.com>
Subject RE: HTTP Basic Authentication Is there hope?
Date Mon, 12 Feb 2007 14:27:12 GMT


Thanks for the feedback, Polar, some comments inline though ...

> -----Original Message-----
> From: Polar Humenn [mailto:phumenn@iona.com] 
> Sent: 11 February 2007 17:13
> To: cxf-dev@incubator.apache.org; eng-tandoori@iona.com
> Subject: HTTP Basic Authentication Is there hope?
> 
> The current way http auth is set up in CXF is to use Spring 
> configuration to on HTTPConduit, like so in a file like "client.xml".
> 
>     <bean
> name="{http://apache.org/hello_world_soap_http}Greeter.http-conduit" 
> abstract="true">    
>         <property name="authorization">
>             <value>
>                 <sec:authorization>
>                     <sec:UserName>Polar</sec:UserName>
>                     <sec:Password>querty</sec:Password>
>                 </sec:authorization>
>             </value>
>         </property>
>     </bean>
> 
> This approach looks less like "having security" and more like 
> "getting around the *problem* of security".

Well it's a very simple placeholder that presumably we can build on. I
don't think it makes any value judgements one way or the other about
security in general.
 
> Aside from the *bad practice* of keeping user name/password 
> combinations in unencrypted files, 

I don't agree with you here that this is necessarily bad practice. In
fact some form of it seems unavoidable to me in the general case.

The username/passwd has to come from somewhere, and for unattended
clients, this somewhere has to be a static repository of some kind. If
this repository is itself secured (e.g. is an encrypted file as you
suggest), then surely in order access this info we'd need a further
"secret" (i.e. a password or key)? So all you've done is pushed the
"secret" retrieval problem around ... now instead of having a Basic auth
username/password in a plaintext file, you'd need the key protecting the
Basic auth username/password to itself be in the clear somewhere, no?

It seems to me that at some point you have to trust the O/S-level file
protection (e.g. Unix-style file permissions).

Unless of course you just assume that every client app has a user
sitting there ready to type in a username & password (or more likely,
transcribe these from a yellow sticky postIt :). For these attended
clients, a simple callback to allow the app prompt the user for creds
would be sufficient and easy to implement. But this is not IMO a
general-purpose replacement for statically configured creds.

> this approach is also 
> subtly bad in that assumes that you know what servers you are 
> going to apriori. The configuration of the http-conduit bean 
> is not server specific, but type specific. I may very well 
> have two different servers offering the same service. One 
> trustworthy, and one rogue (collecting passwords). Confusion 
> may ensue in a more dynamic environment, let's say if I get 
> my WSDL port/endpoint information from an untrusted source 
> like a UDDI server, or my dead grandmother. Another scenario 
> is if I am building for example, an application that uses the 
> same "standard" service offered by two different Banks, I 
> can't use this approach unless I have the same username and 
> password at both banks.

Who ever claimed basic auth was anything other than, well, basic? And
very, very basic at that. Even the relevant RFC describes it as being at
the weak end of the auth spectrum, vulnerable to fairly obvious attacks.

In particular, since the creds are effectively sent in the clear (modulo
base-64 encoding), surely if we want to keep these creds secret, then it
makes absolutely no sense to use basic auth over plain ol' HTTP? 

Rather, auth based on this scheme should *only* be used over HTTPS. In
which case, the WSDL retrieved via ouija board from your dear departed
granny won't fool our client, as the server-provided cert won't be
signed by a CA trusted by virtue of its cert featuring in the client's
truststore.

We could enforce this by ensuring that the AuthPolicy is accompanied by
an appropriate setting of the SSLClientPolicy. But forcing the issue has
the downside of excluding a valid "weak auth" use-case ... e.g. where we
don't care if the creds are stolen because they're not protecting
anything sensitive, but instead just drive some insecure personalization
logic in the endpoint. Or say the VPN use-case, where HTTP is OK as its
tunneled securely.
 
> We would like to examine certain aspects of the endpoint 
> before we start *exposing usernames and passwords to 
> everybody* with a pretty flower. 
> There is no apparent way to do this in CXF's use of HTTP.

Well to an extent there is some control here - we can configure the
SSLClientPolicy to require that the endpoint has a trusted cert.
 
> Furthermore, the HTTP protocol requires that a 401 status be 
> returned from the server if the authorization information is 
> not supplied or incorrect. The 401 response comes back with 
> authorization challenge information, namely the "realm" 
> identifier, which CXF HTTP ignores.

Yes, clearly the realm should be used to identify which creds we sent
(e.g. the Authorization policy should be changed so as to encapsulate
multiple username/passwd pairs, each associated with a specific realm,
plus probably the target URI also).
 
> Internally, CXF uses java.net.HttpURLConnection on the client 
> side, which is really the implementation 
> sun.net.www.protocol.http.HttpURLConnection. This 
> implementation catches the 401 response message and attempts 
> to authenticate [see below], however, it fails with the 
> HTTPRetryException. This exception is caught and turned into 
> a message fault, now allowing us to get any information. 
> It fails oddly because the HTTPConduit's default is to "stream". 
> Streaming is configurable on the endpoint http-conduit 
> HTTPClientPolicy.
> 
> I can construct a complex graph of interceptors on the server 
> side to send the 401 and the proper realm information.

A complex graph of interceptors just to send a 401?

Can you describe what server-side interceptors chains you needed to
achieve this? If something so simple as rejecting an incoming request
with an auth challenge requires some complex choreography in the
server-side interceptors chains, then we are surely doing something very
wrong in our interceptor/dispatch architecture.
 
> However, it fails on the client side in HttpURLConnection
> with an HTTPRetryException, on getInputStream, which is 
> ignored by HTTPConduit. The error is "cannot retry due to 
> server authentication while streaming".

Probably need to turn off chunking here.
  
> The java.net.HttpURLConnection does have an authenticator 
> scheme that allows "automatic" use of Password 
> Authentication, java.net.Authenticator. This Authenticator, 
> (apparently only one per JVM), has an interface with which to 
> query certain aspects of the site "requesting" 
> authentication, such as IP address, port numbers, URL, etc. 
> This object does provide differentiation of figuring out 
> which username and passwords to send, but is slightly lacking 
> in deciding trust whether to send them or not.
> 
> The big question is, can we do better than this? Can we 
> organize something in CXF that will allow us to use security 
> in a good way? First establishing trust before sending 
> sensitive information? 

Ok what we do now is what you might call preemptive auth, in the sense
that we send the Authorization header up-front without waiting to be
asked for it via a 401 challenge. Yes we could wait for the 401, but in
either case, trust establishment cannot be done via Basic auth alone.
IMO at least in order to mean anything, its got to be coupled with
HTTPS.

> Can we do this without solely 
> programming everything into an XML file?

As explained above, for the general case of an unattended client, we
need some way of accessing the creds from a static repository. Whether
this is XML config fragment, or something more fancy like an encrypted
file, surely at some point a secret must be stored in the clear, so it
amounts to effectively the same thing?
 
> Even this java.net.Authenticator is woefully inadequate as 
> there is now way too look up an SSL authentication on the 
> HttpURLConnection.

Do we really need to access the full details of the SSL authentication
at this point? Would a check via Authenticator.getProtocol() that HTTPS
was indeed used, coupled with the client's knowledge of and control over
its own local truststore, not be sufficient?

> I don't imagine that the use of HttpURLConnection will go 
> away inside CXF, 

Well, we could actually consider using the Jakarta Commons HTTPClient as
an alternative, if the java.net.Authenticator mechanism really is so
woeful. HTTPClient allows some extra flexibility in terms of choosing
between pre-emptive and reactive provision of creds, but I'm not sure if
it will give us much more than the
java.net.HttpUrlConnection/Authenticator mechanisms.

> but there should be some better way to 
> "configure" or at least dynamically direct the HTTPConduit in 
> use for a particular endpoint. 
> Would it be beneficial to the team for me to spend time on 
> proposing a good security solution?

Here's the crux of the issue, what's a "good security solution", and
what sort of underlying mechanism is required to supply this goodness?
Is it reasonable to expect to able to build "hardened" security on a
foundation as shaky as Basic auth? There are other, less weak, HTTP
authorization mechanisms (Digest, NTLM etc.) that we could consider
instead.

/Eoghan

Mime
View raw message