cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Polar Humenn <phum...@iona.com>
Subject Re: HTTP Basic Authentication Is there hope?
Date Wed, 14 Feb 2007 19:45:08 GMT
Eoghan,

Thanks. I originally threw a fault, because I didn't know how to prevent 
the message from continuing to the end of the chain (to the 
application). Also, the Fault, seems to use the system to create the 
return "fault" message, and I had thought that is the proper way to go.

Creating a corresponding "out" message to match the "in" message seems 
like the proper way to go since you have the correlation right there. 
But, you seem to usurp the OutInterceptor chain, if not the 
OutFaultInterceptor chain, (which incidentally leads me to doubt the 
need for "Fault" messages.  They are just messages, aren't they?) I 
guess you can just set up the interceptor chains, and call them.

However, I'm still concerned about the fact that that some interceptors 
don't get notified that the chain did not complete.

Cheers,
-Polar

Glynn, Eoghan wrote:
> Hi Polar,
>
> It struck me that sending a 401 has got to be simpler than what you did,
> so I had a crack at knocking up a single interceptor to do the job as
> directly as possible, say sending a 401 with "realm=foo" for the first
> incoming request. I've appended the code below as the Apache mail server
> strips out attachements. Obvioiusly this code needs extending, but you
> could use it as a basic template.
>
> The first mistake you made was to raise a fault. A 401 is not in my view
> a fault, i.e. it wouldn't translate into a HTTP entity-body containing a
> <SOAP:Fault>. In fact what we need is an *empty* response, as all the
> relevant info is carried in the HTTP headers (i.e. the 401 response code
> and WWW-Authenticate header). Similarly we don't want traverse the
> out-fault-chain, rather it would be more appropriate to abort the
> traversal of the in-chain and allow the transport get straight back with
> the challenge.
>
> Cheers,
> Eoghan
>
>   
>> -----Original Message-----
>> From: Polar Humenn [mailto:phumenn@iona.com] 
>> Sent: 12 February 2007 19:13
>> To: cxf-dev@incubator.apache.org
>> Subject: Re: HTTP Basic Authentication Is there hope?
>>
>> Glynn, Eoghan wrote:
>>     
>>>> 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
>>>   
>>>       
>> Well, I tell you what I did.  I am still somewhat naive about 
>> this so, please tell me if I have gone astray. This is where 
>> I was learning about interceptors, and when handleMessage and 
>> handleFault gets called. I think I'm better informed at that 
>> now, but I still may be lacking in some aspects.
>>
>> I set up one Inbound interceptor on the RECEIVE phase to 
>> check for the authorization information if present and 
>> validate it. If it wasn't there or validated I throw a Fault, 
>> which was subclassed to HTTPBAFault, which held the realm identifier.
>>
>> This Inbound InterceptorChain unwinds through the InboundChain. In
>> handleFault() I tried setting the response code, but that was 
>> ineffective, as I realized I was not really manipulating a 
>> response here. so I know I couldn't do this entirely in one 
>> interceptor. Fair enough.
>>
>> Throwing the Fault, I found, automatically generates a 
>> response message, which seems to know its a"fault" message 
>> with a response code of 500 and heads out in an Outbound 
>> Fault Interceptor Chain using handleMessage() calls.
>>
>> I set up a second interceptor that gets installed 
>> (dynamically?) on the OutFaultInterceptor chain on the 
>> USER_STREAM phase. I discoverd some state saved on the 
>> message in the previous interceptor chain, which was the 
>> actual HTTPBAFault I threw, which I discovered is available 
>> through a Message.getContent(Exception.class) call. Then I 
>> changed the response code from 500 to a 401 and had to add 
>> the Authorization header with the realm information.
>>
>> I am not sure if I got the phases right for this sort of 
>> thing (I played with these with varying degrees of success 
>> and failure), or even if I took the right approach. I  may be 
>> relying on some technique or information that is coincidental 
>> and not guaranteed.
>>
>> Cheers,
>> -Polar
>>     
>
>
> /**
>  * Licensed to the Apache Software Foundation (ASF) under one
>  * or more contributor license agreements. See the NOTICE file
>  * distributed with this work for additional information
>  * regarding copyright ownership. The ASF licenses this file
>  * to you under the Apache License, Version 2.0 (the
>  * "License"); you may not use this file except in compliance
>  * with the License. You may obtain a copy of the License at
>  *
>  * http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing,
>  * software distributed under the License is distributed on an
>  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>  * KIND, either express or implied. See the License for the
>  * specific language governing permissions and limitations
>  * under the License.
>  */
>
> package org.apache.cxf.interceptor;
>
> import java.io.IOException;
> import java.io.OutputStream;
> import java.net.HttpURLConnection;
> import java.util.Arrays;
> import java.util.List;
> import java.util.Map;
>
> import org.apache.cxf.endpoint.Endpoint;
> import org.apache.cxf.message.Exchange;
> import org.apache.cxf.message.Message;
> import org.apache.cxf.phase.AbstractPhaseInterceptor;
> import org.apache.cxf.phase.Phase;
> import org.apache.cxf.transport.Conduit;
> import org.apache.cxf.ws.addressing.EndpointReferenceType;
>
> public class ChallengeInterceptor extends
> AbstractPhaseInterceptor<Message> {
>
>     boolean challenged;
>     
>     public ChallengeInterceptor() {
>         super();
>         setPhase(Phase.RECEIVE);
>     }
>
>     public void handleMessage(Message inMessage) {
>         if (!challenged) {
>             Message outMessage = getOutMessage(inMessage);
>             outMessage.put(Message.RESPONSE_CODE,
> HttpURLConnection.HTTP_UNAUTHORIZED);
>             setHeader(outMessage, "WWW-Authenticate", "Basic
> realm=foo");
>             inMessage.getInterceptorChain().abort();
>             try {
>                 getConduit(inMessage).send(outMessage);
>                 close(outMessage);
>             } catch (IOException ioe) {
>                 // REVISIT log etc...
>                 ioe.printStackTrace();
>             }
>             challenged = true;
>         }
>     }
>
>     private Message getOutMessage(Message inMessage) {
>         Exchange exchange = inMessage.getExchange();
>         Message outMessage = exchange.getOutMessage();
>         if (outMessage == null) {
>             Endpoint endpoint = exchange.get(Endpoint.class);
>             outMessage = endpoint.getBinding().createMessage();
>             exchange.setOutMessage(outMessage);
>         }
>         outMessage.putAll(inMessage);
>         return outMessage;
>     }
>
>     @SuppressWarnings("unchecked")
>     private void setHeader(Message message, String name, String value) {
>         Map<String, List<String>> responseHeaders =
>             (Map<String,
> List<String>>)message.get(Message.PROTOCOL_HEADERS);
>         if (responseHeaders != null) {
>             responseHeaders.put(name, Arrays.asList(new
> String[]{value}));
>         }
>     }
>     
>     private Conduit getConduit(Message inMessage) throws IOException {
>         Exchange exchange = inMessage.getExchange();
>         EndpointReferenceType target =
>             exchange.get(EndpointReferenceType.class);
>         Conduit conduit =
>             exchange.getDestination().getBackChannel(inMessage, null,
> target);
>         exchange.setConduit(conduit);
>         return conduit;
>     }
>     
>     private void close(Message outMessage) throws IOException {
>         OutputStream os = outMessage.getContent(OutputStream.class);
>         os.flush();
>         os.close();
>     }
> }
>
>
>
>  
>   


Mime
View raw message