You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cxf.apache.org by Polar Humenn <ph...@iona.com> on 2007/02/11 18:13:27 UTC

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".

Aside from the *bad practice* of keeping user name/password combinations 
in unencrypted files, 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.

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.

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.

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. 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".
 
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? Can we do this 
without solely programming everything into an XML file?

Even this java.net.Authenticator is woefully inadequate as there is now 
way too look up an SSL authentication on the HttpURLConnection.

I don't imagine that the use of HttpURLConnection will go away inside 
CXF, 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?

Cheers,
-Polar


Re: HTTP Basic Authentication Is there hope?

Posted by Polar Humenn <ph...@iona.com>.
Daniel Kulp wrote:
> Polar,
>
> On Monday 12 February 2007 16:00, Polar Humenn wrote:
>   
>> Daniel Kulp wrote:
>>     
>>> On Sunday 11 February 2007 16:21, Dan Diephouse wrote:
>>>       
>>>> As a side note, do we really think http chunking should be on by
>>>> default? We ended up making users having to turn it on in XFire because
>>>> of interoperability issues with various HTTP servers. So it makes me
>>>> nervous to default to having chunking on.
>>>>         
>>> If chunking is not turned off (or redirects turned on BTW), then
>>> streaming is effectively disabled and performance for large messages
>>> drops significantly (and memory usage goes way up).   The
>>> HTTPUrlConnection object buffers the entire message into a byte[] so that
>>> it can calculate the Content-Length header (if one isn't specified which
>>> we don't calculate) or resend if it gets a 30# response code.   With
>>> chunking, the Content-Lenght header is not needed so if redirect support
>>> is off, it can stream directly.   However, that also breaks the 401
>>> resend.
>>>
>>>
>>> What we could do is disable chunking if there is a 401 callback
>>> registered and the we're already not authenticated.  If there is a basic
>>> auth header to go out (AuthenticationPolicy object filled out), keep the
>>> chunking.
>>>       
>> Can chunking be turned on a connection after an authentication? Is that
>> allowed?
>>     
>
> On subsequent request, yes.   Shouldn't be a big deal.
>
>
>   
>>> Couple caveats/use cases that must be supported:
>>> 1) If there isn't a callback and we get a 401,  we must throw a proper
>>> exception that is propagated back with all useful information to the
>>> user.
>>>       
>> That currently does not happen because the HttpURLConnection
>> implementation hides the needed information. I am now looking into the
>> Jakara commons HTTPClient, which looks quite promising, if it works like
>> it web page says.
>>     
>
> Are you sure?    What information is missing?
>
> I seem to be able to get all the information for basic auth....
>
> connect.getResponseCode() returns 401
> connect.getHeaderFields().get("WWW-Authenticate") returns Basic realm="WebDAV 
> Restricted" for my webdav site.
>
> If you wait until you call getInputStream() and catch that exception, the 
> information is indeed gone.    If you grab the code and HeaderFields first, 
> it seems to be there.  (and note that other stuff would be in the 
> ErrorStream, not the InputStream)'
>   
Yep, the HTTPConduit implementation right now currently just goes for 
the getInputStream() and then that's when the Conduit caught the error 
about authentication during streaming.  So, it would be easy enough to 
get the realm information needed and throw it back, but what about a 
retry after a call back? If we do this in the Conduit, we might be doing 
just as much work as this Jakarta HTTPClient does already.

The implementation of java.net is still lacking, (as coincidently the 
Jakarta HTTPClient web state says). Before one gives up the sensitive 
username/password information one would like to examine the SSL 
information of the server and protection quality of the "tunnel" to it.

Unfortunately, at a look at the Jakarta code, I think the HTTPClient 
missed the boat in terms of this assurance as well. Although it allows 
to use SSLSocket Factories, its authentication callback does not let you 
get at the information from that socket. I may be wrong, but I've been 
looking at it all afternoon, I don't think so.

> Thanks!
>   


Re: HTTP Basic Authentication Is there hope?

Posted by Daniel Kulp <da...@iona.com>.
Polar,

On Monday 12 February 2007 16:00, Polar Humenn wrote:
> Daniel Kulp wrote:
> > On Sunday 11 February 2007 16:21, Dan Diephouse wrote:
> >> As a side note, do we really think http chunking should be on by
> >> default? We ended up making users having to turn it on in XFire because
> >> of interoperability issues with various HTTP servers. So it makes me
> >> nervous to default to having chunking on.
> >
> > If chunking is not turned off (or redirects turned on BTW), then
> > streaming is effectively disabled and performance for large messages
> > drops significantly (and memory usage goes way up).   The
> > HTTPUrlConnection object buffers the entire message into a byte[] so that
> > it can calculate the Content-Length header (if one isn't specified which
> > we don't calculate) or resend if it gets a 30# response code.   With
> > chunking, the Content-Lenght header is not needed so if redirect support
> > is off, it can stream directly.   However, that also breaks the 401
> > resend.
> >
> >
> > What we could do is disable chunking if there is a 401 callback
> > registered and the we're already not authenticated.  If there is a basic
> > auth header to go out (AuthenticationPolicy object filled out), keep the
> > chunking.
>
> Can chunking be turned on a connection after an authentication? Is that
> allowed?

On subsequent request, yes.   Shouldn't be a big deal.


> > Couple caveats/use cases that must be supported:
> > 1) If there isn't a callback and we get a 401,  we must throw a proper
> > exception that is propagated back with all useful information to the
> > user.
>
> That currently does not happen because the HttpURLConnection
> implementation hides the needed information. I am now looking into the
> Jakara commons HTTPClient, which looks quite promising, if it works like
> it web page says.

Are you sure?    What information is missing?

I seem to be able to get all the information for basic auth....

connect.getResponseCode() returns 401
connect.getHeaderFields().get("WWW-Authenticate") returns Basic realm="WebDAV 
Restricted" for my webdav site.

If you wait until you call getInputStream() and catch that exception, the 
information is indeed gone.    If you grab the code and HeaderFields first, 
it seems to be there.  (and note that other stuff would be in the 
ErrorStream, not the InputStream)

Thanks!
-- 
J. Daniel Kulp
Principal Engineer
IONA
P: 781-902-8727    C: 508-380-7194
daniel.kulp@iona.com

Re: HTTP Basic Authentication Is there hope?

Posted by Polar Humenn <ph...@iona.com>.
Daniel Kulp wrote:
> On Sunday 11 February 2007 16:21, Dan Diephouse wrote:
>   
>> As a side note, do we really think http chunking should be on by default?
>> We ended up making users having to turn it on in XFire because of
>> interoperability issues with various HTTP servers. So it makes me nervous
>> to default to having chunking on.
>>     
>
> If chunking is not turned off (or redirects turned on BTW), then streaming is 
> effectively disabled and performance for large messages drops significantly 
> (and memory usage goes way up).   The HTTPUrlConnection object buffers the 
> entire message into a byte[] so that it can calculate the Content-Length 
> header (if one isn't specified which we don't calculate) or resend if it gets 
> a 30# response code.   With chunking, the Content-Lenght header is not needed 
> so if redirect support is off, it can stream directly.   However, that also 
> breaks the 401 resend.
>
>
> What we could do is disable chunking if there is a 401 callback registered and 
> the we're already not authenticated.  If there is a basic auth header to go 
> out (AuthenticationPolicy object filled out), keep the chunking.   
>   

Can chunking be turned on a connection after an authentication? Is that 
allowed?

>> 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? Can we do this
>>> without solely programming everything into an XML file?
>>>
>>> Even this java.net.Authenticator is woefully inadequate as there is now
>>> way too look up an SSL authentication on the HttpURLConnection.
>>>
>>> I don't imagine that the use of HttpURLConnection will go away inside
>>> CXF, 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?
>>>       
>
>
> Couple caveats/use cases that must be supported:
> 1) If there isn't a callback and we get a 401,  we must throw a proper 
> exception that is propagated back with all useful information to the user.
>   

That currently does not happen because the HttpURLConnection 
implementation hides the needed information. I am now looking into the 
Jakara commons HTTPClient, which looks quite promising, if it works like 
it web page says.

> 2) If the user has specified a username/password programatically (ex: 
> BindingProvider keys from JAX-WS frontend), we need to put them on the wire 
> immediately, even if it's just http. (spec compliance)
>   

Okay. If that's what the user wants, that's what he gets! :)

> I'm not going to pretend to understand half of what this thread is talking 
> about (I'm not a security expert by any means), but the "simple" usecases 
> need to be the defaults due to JAX-WS spec compliance.

Surely, please keep us in line on these issues. I am not all that 
familiar with JAX-WS, but I'm learning.

Cheers,
-Polar

Re: HTTP Basic Authentication Is there hope?

Posted by Daniel Kulp <da...@iona.com>.
On Sunday 11 February 2007 16:21, Dan Diephouse wrote:
> As a side note, do we really think http chunking should be on by default?
> We ended up making users having to turn it on in XFire because of
> interoperability issues with various HTTP servers. So it makes me nervous
> to default to having chunking on.

If chunking is not turned off (or redirects turned on BTW), then streaming is 
effectively disabled and performance for large messages drops significantly 
(and memory usage goes way up).   The HTTPUrlConnection object buffers the 
entire message into a byte[] so that it can calculate the Content-Length 
header (if one isn't specified which we don't calculate) or resend if it gets 
a 30# response code.   With chunking, the Content-Lenght header is not needed 
so if redirect support is off, it can stream directly.   However, that also 
breaks the 401 resend.


What we could do is disable chunking if there is a 401 callback registered and 
the we're already not authenticated.  If there is a basic auth header to go 
out (AuthenticationPolicy object filled out), keep the chunking.   


> 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? Can we do this
> > without solely programming everything into an XML file?
> >
> > Even this java.net.Authenticator is woefully inadequate as there is now
> > way too look up an SSL authentication on the HttpURLConnection.
> >
> > I don't imagine that the use of HttpURLConnection will go away inside
> > CXF, 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?


Couple caveats/use cases that must be supported:
1) If there isn't a callback and we get a 401,  we must throw a proper 
exception that is propagated back with all useful information to the user.

2) If the user has specified a username/password programatically (ex: 
BindingProvider keys from JAX-WS frontend), we need to put them on the wire 
immediately, even if it's just http. (spec compliance)

I'm not going to pretend to understand half of what this thread is talking 
about (I'm not a security expert by any means), but the "simple" usecases 
need to be the defaults due to JAX-WS spec compliance. 

-- 
J. Daniel Kulp
Principal Engineer
IONA
P: 781-902-8727    C: 508-380-7194
daniel.kulp@iona.com

Re: HTTP Basic Authentication Is there hope?

Posted by Dan Diephouse <da...@envoisolutions.com>.
Hi Polar,

Comments inline...

On 2/11/07, Polar Humenn <ph...@iona.com> wrote:
>
> 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".
>
> Aside from the *bad practice* of keeping user name/password combinations
> in unencrypted files, 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.


This is one of the things that rubs me wrong about the Configurable
approach. Something that I would like to see is an approach where we create
client beans in the spring context and use those:

<jaxws:client id="myGreeter1" class="....Greeter">
  <jaxws:replyTo>...</jaxws:replyTo>
  <jaxws:conduit>#basicConduitConfig</jaxws:conduit>
</jaxws:client>

<http:conduit id="basicConduitConfig"> .... </http:conduit>

That way the http:conduit definition would only apply to that Client (or any
others you wanted it to apply to). This would be a slightly different
approach in that instead of apply XML configuration to objects you've
created outside the ApplicationContext, you would be creating objects inside
the ApplicationContext. You would then either pull the objects outside the
context via "context.getBean("myGreeter1")" or you'd inject your client into
your application somewhere.

Would that help address some concerns? I think the goal behind the current
approach was to allow you to create an Endpoint via Endpoint.publish and
just configure the HTTP part of it without having to do all the extra XML.
So its a bit of a trade off...

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.
>
> 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.
>
> 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. 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".


I'm not sure what the issue is here...

As a side note, do we really think http chunking should be on by default? We
ended up making users having to turn it on in XFire because of
interoperability issues with various HTTP servers. So it makes me nervous to
default to having chunking on.

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? Can we do this
> without solely programming everything into an XML file?
>
> Even this java.net.Authenticator is woefully inadequate as there is now
> way too look up an SSL authentication on the HttpURLConnection.
>
> I don't imagine that the use of HttpURLConnection will go away inside
> CXF, 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?


If you would like to propose a better option I am all for it. I am no
security expert, but would a callback mechanism help address some of the
concerns? I wonder if we can create a mechanism that works well with both
transport level security and message level security (i.e. ws-security).

Thanks for bringing these things up, these are definitely issues!

- Dan

P.S. - Is it necssary to CC a private mailing list that not everyone can
access?


-- 
Dan Diephouse
Envoi Solutions
http://envoisolutions.com | http://netzooid.com/blog

Re: HTTP Basic Authentication Is there hope?

Posted by Sergey Beryozkin <se...@iona.com>.
Hi


> 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".
> 

Why don't have a simple interface like AuthorizationProvider ot something like that :

             <sec:authorization>
                    <sec:provider>AuthorizationProviderImpl</sec:provider>
              </sec:authorization>

and then have to analyze whatever info you can provider it and give you the required credentials ?

Cheers, Sergey