You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Johannes Michler <or...@gmail.com> on 2010/07/19 20:20:08 UTC

CXFAuthenticator causing "ProtocolException: Server redirected too many times (20)" instead of HTTP-401 when providing wrong credentials

Hi,

we're using Apache CXF 2.2.9 to access a webservice. The service is served
on a tomcat-server (using the cxf-servlet, but this is not important here)
and protected by requiring http basic auth. When supplying correct
username/password-data in our client this works as expected when using the
following code:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass( IReferenceManagerImpl.class);
        factory.setAddress( wsAddress.toString());
        factory.setUsername( horus_user);
        factory.setPassword( horus_password);

        IReferenceManagerImpl implementation = ( IReferenceManagerImpl)
factory.create();
//afterwards we're setting allowChunking to false for our http-client-policy
since chunking gives us some problem with oracle webcache, but this isn't
the point here...

However, when the user supplied a wrong password, things go wrong. Instead
of CXF to give me a HTTP 401 Exception code it tries for many times to
authenticate against the server (20 times I think) and finally gives me the
following exception:

Caused by: java.net.ProtocolException: Server redirected too many  times
(20)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown
Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:2165)


This is fatal for us, since after so much error-nous tries our ldap-server
locks the user that provide a wrong password.

I tracked down the issue and found out that the Sun HttpURLConnection asks
the default Authenticator for username/password when getting 401. This
repeats in a loop for I think 20 times. Unfortunately, CXF set the default
Authenticator to CXFAuthenticator wich provides the username/password on
every consecuting try.

For me there are two possible workarounds:
1) I can set Authenticator.setDefault(null) after CXF set it to
CXFAuthenticator
2) I can do httpConduit.setAuthorization(null) on my HttpConduit.

This doesn't prevent from authorization to work since it seems that CXF sets
the right HTTP-Authorization-Request on the HttpUrlConnection before the
initial try. But when providing wrong credentials I'm getting the HTTP
401-Exception I would excpect.

I'm quite sure this was the default behavior on older cxf-versions. (we
startet with 2.2.2)

Isn't it bad style to try to authenticate over and over again with the same
credentials? What is that CXFAuthenticator actually good for? And wich of my
workarounds is actually "better"? Do they have side-effects I cannot see at
the moment?


Best regards
Johannes

Re: CXFAuthenticator causing "ProtocolException: Server redirected too many times (20)" instead of HTTP-401 when providing wrong credentials

Posted by Daniel Kulp <dk...@apache.org>.

This actually sounds like a bug in the HttpURLConnection.   Not sure why it 
would keep sending the request like that.  

Can you try messing with some of the other settings to see if they would help.   
In particular, try turning ON the autoRedirect or turning the maxRetransmits 
up to 2 or something.   Maybe keeping chunking on, but setting the 
ChunkingThreshold to something larger than any message you might be setting.   
One of those MAY help as we'd end up caching things and possibly handling the 
401 ourself (which would throw an exception).

Beyond that, we would need to update the CXFAuthenticator somehow.   Most 
likely, I would do something like:

        Message m = PhaseInterceptorChain.getCurrentMessage();
        if (m != null) {
            if (m.containsKey(CXFAuthenticator.class.getName() + 
getRequestorType().toString())) {
                return auth;
            }
            m.put(CXFAuthenticator.class.getName() + 
getRequestorType().toString(),
                  Boolean.TRUE);
 ......

to make it only trigger once per message.   

Is there anyway you could test that change? 

As a little history, the CXFAuthenticator was added I think in 2.2.6 for two 
use cases:

1) NTLM authentication - to use the NTLM stuff built into Java6, we need to 
pass the auth creds via the Authenticator.   

2) SSL proxy authentication - there isn't a way to use a Proxy server via SSL 
and using authentication with that proxy without a Authenticator.  

Thus, the CXFAuthenticator was added to get those cases working.


Dan



On Monday 19 July 2010 2:20:08 pm Johannes Michler wrote:
> Hi,
> 
> we're using Apache CXF 2.2.9 to access a webservice. The service is served
> on a tomcat-server (using the cxf-servlet, but this is not important here)
> and protected by requiring http basic auth. When supplying correct
> username/password-data in our client this works as expected when using the
> following code:
> 
> JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
>         factory.setServiceClass( IReferenceManagerImpl.class);
>         factory.setAddress( wsAddress.toString());
>         factory.setUsername( horus_user);
>         factory.setPassword( horus_password);
> 
>         IReferenceManagerImpl implementation = ( IReferenceManagerImpl)
> factory.create();
> //afterwards we're setting allowChunking to false for our
> http-client-policy since chunking gives us some problem with oracle
> webcache, but this isn't the point here...
> 
> However, when the user supplied a wrong password, things go wrong. Instead
> of CXF to give me a HTTP 401 Exception code it tries for many times to
> authenticate against the server (20 times I think) and finally gives me the
> following exception:
> 
> Caused by: java.net.ProtocolException: Server redirected too many  times
> (20)
> at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown
> Source)
> at java.net.HttpURLConnection.getResponseCode(Unknown Source)
> at
> org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleRespons
> eInternal(HTTPConduit.java:2165)
> 
> 
> This is fatal for us, since after so much error-nous tries our ldap-server
> locks the user that provide a wrong password.
> 
> I tracked down the issue and found out that the Sun HttpURLConnection asks
> the default Authenticator for username/password when getting 401. This
> repeats in a loop for I think 20 times. Unfortunately, CXF set the default
> Authenticator to CXFAuthenticator wich provides the username/password on
> every consecuting try.
> 
> For me there are two possible workarounds:
> 1) I can set Authenticator.setDefault(null) after CXF set it to
> CXFAuthenticator
> 2) I can do httpConduit.setAuthorization(null) on my HttpConduit.
> 
> This doesn't prevent from authorization to work since it seems that CXF
> sets the right HTTP-Authorization-Request on the HttpUrlConnection before
> the initial try. But when providing wrong credentials I'm getting the HTTP
> 401-Exception I would excpect.
> 
> I'm quite sure this was the default behavior on older cxf-versions. (we
> startet with 2.2.2)
> 
> Isn't it bad style to try to authenticate over and over again with the same
> credentials? What is that CXFAuthenticator actually good for? And wich of
> my workarounds is actually "better"? Do they have side-effects I cannot
> see at the moment?
> 
> 
> Best regards
> Johannes

-- 
Daniel Kulp
dkulp@apache.org
http://dankulp.com/blog