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 Thu, 15 Feb 2007 10:48:17 GMT

Polar,

On the issue of usurping the Out{Fault}Interceptor chains, my thinking
it that we're not actually sending back a real out message per se. For a
start it would never make any sense for this "message" to have any
content. Instead we're *rejecting* the incoming message using a
transport mechanism specific to HTTP, i.e. the 401 challenge. 

So we're not responding with a message which completes the twoway MEP,
rather we're using a transport-specific mechanism to invite the client
to *resubmit* the initial message, only this time adorned with an extra
header containing the Basic auth creds. This resubmitted request will
then responded to with a proper reply message, which will traverse the
Out{Fault}Interceptor chains as expected.

In sense a 401 is like an invitation to rewind the MEP and replay the
initial message in slightly modified form.

Any interceptors prior to the ChallengeInterceptor could be notified
that the chain did not complete by virtue of the proposed
onTermination()/onComplete() semantics (which you've poured cold water
on in the "Proposal for chaning CXF Interceptor APIs. WAS: RE: When
should we close the handlers in CXF?" thread ... I'll throw in my 2 euro
cents on that thread shortly).

Cheers,
Eoghan

> -----Original Message-----
> From: Polar Humenn [mailto:phumenn@iona.com] 
> Sent: 14 February 2007 19:45
> To: cxf-dev@incubator.apache.org
> Subject: Re: HTTP Basic Authentication Is there hope?
> 
> 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