You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by dmadunic <do...@gmail.com> on 2007/08/28 12:14:19 UTC

WS-Security and CXF

Hi all,
i have two questions concerning how to implement WS-Security with CXF.

1) First question: how on the server side to read CallbackHandler supplied
password?

Followoing instructions on CXF homesite and from several articles, I have
created simple HelloWorldService and attached to it following interceptors:

	<jaxws:endpoint  id="helloWorld" implementor="demo.spring.HelloWorldImpl"
address="/HelloWorld" >
		<jaxws:inInterceptors>
			<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
			<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
				<property name="properties">
					<map>
						<entry key="action" value="UsernameToken"/>
						<entry key="passwordType" value="PasswordText"/>
						<entry key="passwordCallbackClass"
value="demo.interceptors.AuthenticationCallbackHandler"/>
					</map>
				</property>
			</bean>
			<bean class="demo.interceptors.ValidateUserTokenInterceptor"/>
		</jaxws:inInterceptors>

	</jaxws:endpoint>

AuthenticationCallbackHandler is very simple it just does the following:

public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
		
		if (pc.getIdentifer().equals("joe")) {
			pc.setPassword("password");
		}
	}

I also wrote my demo.interceptors.ValidateUserTokenInterceptor which should
Validate received token. 

public void handleMessage(Message message) throws Fault {
		boolean userTokenValidated = false;

		logger.debug("Invoked - ValidateUserToken: " + message);

		//logger.debug("messagePwd: " + message.get);
		Vector result = (Vector)
message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);

		if (result==null) {
			throw new IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
Property not found in MessageContext?!");
		}

		for (int i = 0; i < result.size(); i++) {
			WSHandlerResult res = (WSHandlerResult) result.get(i);
			for (int j = 0; j < res.getResults().size(); j++) {
				WSSecurityEngineResult secRes = (WSSecurityEngineResult)
res.getResults().get(j);
				int action = secRes.getAction();
				logger.debug("Checking: " + secRes);
				// USER TOKEN
				if ((action & WSConstants.UT) > 0) {
					WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal)
secRes.getPrincipal();
					logger.debug("name=" + principal.getName());
					logger.debug("password=" + principal.getPassword());
					logger.debug("passwordType=" + principal.getPasswordType());
					logger.debug("createdTime=" + principal.getCreatedTime());

					if (principal.getPassword() == null) {
						throw new RuntimeException("Invalid Security Header");
					} else {
                                                // NOW COMPARE PASSWORDS -
HOW????
						userTokenValidated = true;
					}
				}
			}
		}
		if (!userTokenValidated) {
			throw new RuntimeException("Security processing failed");
		}
	}

So far i was able to read information from WSSE:Security header - ie.
username and pwd supplied by the Client. But i do not know how to address
the password value supplied by AuthenticationCallbackHandler inside this
interceptor??

2) Second question: how to properly configure interceptors on client using
spring?

To test the service i wrote simple HelloClient:

public static void main(String[] args) {

		ApplicationContext context = new
ClassPathXmlApplicationContext("/clientAppContext.xml");
		HelloWorld client = (HelloWorld) context.getBean("client");
		System.out.println("Invoking service...");
		String text = client.sayHi("Domagoj");
		System.out.println("Response=: " + text);
	}

This is my clientAppContext.xml:

<bean id="client" class="demo.spring.HelloWorld" 
factory-bean="clientFactory" factory-method="create"/>

	<bean id="clientFactory"
class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
	  <property name="address"
value="http://localhost:8080/SoaLab/HelloWorld"/>
	  <property name="outInterceptors">
			<list>
				<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
				<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
					<property name="properties">
						<map>
							<entry key="action" value="UsernameToken"/>
							<entry key="user" value="joe"/>
							<entry key="passwordType" value="PasswordText"/>
							<entry key="passwordCallbackClass"
value="demo.interceptors.ClientPasswordCallback"/>
						</map>
					</property>
				</bean>
			</list>
		</property>
	</bean>

The problem i have is that Response i receive from HelloWorld service is
null??
If i comment interceptors on both client and server side it all works fine.

Any suggestions?

Thx in advance....


-- 
View this message in context: http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
Sent from the cxf-user mailing list archive at Nabble.com.


RE: WS-Security and CXF

Posted by dmadunic <do...@gmail.com>.
Colm thx for the code snippet:

> Map<String, Object> properties = ...
> properties.put(WSHandlerConstants.PW_CALLBACK_REF,
> callbackHandlerObject);
> WSS4JInInterceptor inHandler = new WSS4JInInterceptor(properties);

now i managed to configure it through spring with no problem at all, here is
an example for all those who might need it in future:

	<bean id="wss4jOutConfiguration"
class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
		<property name="properties">
			<map>
				<entry key="action" value="UsernameToken Timestamp"/>
				<entry key="user" value="joe"/>
				<entry key="passwordType" value="PasswordDigest"/>
				<entry>
					   <key>
						   <value>passwordCallbackRef</value>
					   </key>
					   <ref bean="usernamePasswordCallback" />
				</entry>
			</map>
		</property>
	</bean>

As for CallbackHandler discussion, i think that team from wss4j should take
a close look at the Spring Acegi code design at the first place. Where no
such ambiguities could be found - that one component in case should performe
one action and in other case something else.
 
One possible solution to resolve this issue would be to introduce 
CredentalsValidator interface which would be called after CallbackHandler in
order to handle password or any other type of credentials validation.
In this way credentials validation logic would be decoupled from Wss4j
Interceptors and assigned to specialized component and responsobilitiy of
CallbackHandler would be clear and simple: that is to retrieve password and
nothing more! In this way method declaradion and corresponding Exception
declartions of CallbackHandler are just fine! If no pwd is found throw No
password exception if it can not access storage throw IOException.

best



O hEigeartaigh, Colm wrote:
> 
> Hi,
> 
> Some comments on your comments...
> 
>> So, first, what do you think would be proper behavioure of
> CallbackHandler
>> in case of authentication failure?
> 
> In the case of authentication failure, I guess you could throw a
> org.apache.ws.security.WSSecurityException in the handle method of your 
> CallbackHandler implementation. WSSecurityException extends 
> java.rmi.RemoteException, which in turn extends java.io.IOException,
> which is explicitly thrown by the handle method, and caught accordingly
> in UsernameTokenProcessor.
> 
> However, the fact that WSSecurityExceptions aren't explicitly caught and
> thrown on in UsernameTokenProcessor is a bug which should be raised with
> WSS4J. Ultimately, the logic for handling a plaintext password derived
> from an incoming UsernameToken needs to be rewritten to separate the
> password callback mechanism from the processing of the password, as is
> done for the digested case.
> 
>> Furthermore, UsernameTokenProcessor converts both of this Exceptions
> to
>> WSSecurityException with "noPassword" message which is actually not
> 
>> correct information, maybe wrong password was supplied, or
> CallbackHandler > could not contact LDAP to chek for password so it
> throwed IOException 
>> which was then converted to also WSSecurityException with noPassword 
>> label?
> 
> This will be fixed by the change that I proposed above. However, note
> that 
> "noPassword" is defined in errors.properties as
> "noPassword=WSSecurityEngine: Callback supplied no password for: {0}",
> so it's not totally cryptic.
> 
>> Second, i would like to know is there a way how one can configure
>> CallbackHandler through Spring application context, and then just pass
>> reference to it to the WSS4jInInterceptor instead of a class name.
> This is
>> especially of handy  if CallbackHandler needs to connect to some
> external
>> storage such as LDAP or DB to retrive pwd.
> 
> You can pass a reference to a callback handler in code with something
> like;
> 
> Map<String, Object> properties = ...
> properties.put(WSHandlerConstants.PW_CALLBACK_REF,
> callbackHandlerObject);
> WSS4JInInterceptor inHandler = new WSS4JInInterceptor(properties);
> 
> Doing this through spring could be tricky though...
> 
> Colm.
> 
> 
> -----Original Message-----
> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
> Sent: 28 August 2007 16:06
> To: cxf-user@incubator.apache.org
> Subject: RE: WS-Security and CXF
> 
> 
> Hi Colm,
> thx for pointing me to the right direction - although i was attempting
> to
> avoid looking at the sources at any cost, especially since this seemed
> to me
> as quite simple task. Anyway, after looking at sources for wss4j and cxf
> I
> now begin to grasp how and what should be done, but still have some
> questions - which are actually more of a comment.
> 
> As far as i can see handling of differnt type of security actions is
> done by
> various classes in wss4j which all implement following interface:
> 
> org.apache.ws.security.processor.Processor
> 
> one of those classes is also UsernameTokenProcessor, which follows the
> behaviour You described in your posts, ie. it will handle everything
> only if
> supplied pwd is hashed otherwise (if for example pwd is Plain text) it
> expects for CallbackHandler to handle things.
> Apart from the fact that this is bad design, since no clear division of
> roles is established, it is not clear what should Callback class do if
> passwords do not match, or if validation fails for some other reasons??!
> 
> Java code that handles this check in UsernameTokenProcessor is as
> follows:
> 
> WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
>                     pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
>             callbacks[0] = pwCb;
>             try {
>                 cb.handle(callbacks);
>             } catch (IOException e) {
>                 throw new
> WSSecurityException(WSSecurityException.FAILURE,
>                         "noPassword", new Object[]{user});
>             } catch (UnsupportedCallbackException e) {
>                 throw new
> WSSecurityException(WSSecurityException.FAILURE,
>                         "noPassword", new Object[]{user});
>             }
> 
> So CallbackHandler has only options of throwing IOException or
> UnsupportedCallbackException, which is neither appropritate exception
> for
> case when authentication failes due to the wrong password.
> Furthermore, UsernameTokenProcessor converts both of this Exceptions to
> WSSecurityException with "noPassword" message which is actually not
> correct
> information, maybe wrong password was supplied, or CallbackHandler could
> not
> contact LDAP to chek for password so it throwed IOException which was
> then
> converted to also WSSecurityException with noPassword label?
> 
> So, first, what do you think would be proper behavioure of
> CallbackHandler
> in case of authentication failure?
> Second, i would like to know is there a way how one can configure
> CallbackHandler through Spring application context, and then just pass
> reference to it to the WSS4jInInterceptor instead of a class name. This
> is
> especially of handy  if CallbackHandler needs to connect to some
> external
> storage such as LDAP or DB to retrive pwd.
> 
> thx
> 
> O hEigeartaigh, Colm wrote:
>> 
>> 
>> WSS4JInInterceptor is an interceptor that processes the WS-Security
>> components of an inbound SOAP message. So for example, in your case
> you
>> need to configure it to process UsernameTokens, and pass it a
>> CallbackHandler implementation so that it knows how to handle the
>> password validation. 
>> 
>> Whether it is a "preparatory interceptor" or not depends on your
>> requirements. You may, for example, want to use the WSS4JInInterceptor
>> to validate the UsernameToken, and then use the username/password for
>> other purposes in another interceptor. But this use case is outside
> the
>> scope of WS-Security, and hence WSS4JInInterceptor does not handle it.
>> 
>> Your best bet in understanding how WSS4JInInterceptor works is to
> peruse
>> the code + look at the unit and system tests. I agree the
> documentation
>> is substandard, I might add improving it to my to-do list ;-)
>> 
>> Colm.
>> 
>> 
>> -----Original Message-----
>> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
>> Sent: 28 August 2007 12:43
>> To: cxf-user@incubator.apache.org
>> Subject: RE: WS-Security and CXF
>> 
>> 
>> Thx a lot Colm,
>> actually i think my problem was that I totally do not understand what
>> does
>> WSS4JInInterceptor do or is supposed to do?
>> 
>> Javadoc for the method handleMessage says only this:
>> 
>> Description copied from interface: Interceptor
>>     Intercepts a message. Interceptors need NOT invoke handleMessage
> or
>> handleFault on the next interceptor - the interceptor chain will take
>> care
>> of this.
>> 
>> which is quite useless ;-(
>> 
>> After seeing examples in CXF User guide i assumed that it was kind of
>> preparatory interceptor - one that will prepare context for further
>> processing - hence the need to configure it with the
>> PasswordCallbackHandler, but it seems it is not so?
>> It would be nice if someone clarified the functionality of this
>> interceptor
>> and what are all of his configuration options. Informatio on
>> http://cwiki.apache.org/CXF20DOC/ws-security.html is very basic and
>> lacking
>> any explanations....
>> 
>> thx
>> 
>> 
>> O hEigeartaigh, Colm wrote:
>>> 
>>> Hi,
>>> 
>>> To answer your first question: To fully understand the semantics of
>>> processing an inbound UsernameToken, you need to examine the
>>> implementation of
>>> org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
>>> Basically, the implementation is as follows:
>>> 
>>> a) Digested Password: Get the original password from the
>> CallbackHandler
>>> implementation, process it accordingly and compare to the received
>>> digested password.
>>> b) Any other Password Type: Delegate all validation to the
>>> CallbackHandler implementation.
>>> 
>>> So how you implement your CallbackHandler implementation depends on
>> your
>>> requirements. At the moment your implementation essentially does no
>>> processing of the password. 
>>> 
>>> So to summarise, any code you have for comparing the password etc.
>>> should be implemented in AuthenticationCallbackHandler, rather than
> in
>>> your ValidateUserTokenInterceptor.
>>> 
>>> Colm.
>>> 
>>> -----Original Message-----
>>> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
>>> Sent: 28 August 2007 11:14
>>> To: cxf-user@incubator.apache.org
>>> Subject: WS-Security and CXF
>>> 
>>> 
>>> Hi all,
>>> i have two questions concerning how to implement WS-Security with
> CXF.
>>> 
>>> 1) First question: how on the server side to read CallbackHandler
>>> supplied
>>> password?
>>> 
>>> Followoing instructions on CXF homesite and from several articles, I
>>> have
>>> created simple HelloWorldService and attached to it following
>>> interceptors:
>>> 
>>> 	<jaxws:endpoint  id="helloWorld"
>>> implementor="demo.spring.HelloWorldImpl"
>>> address="/HelloWorld" >
>>> 		<jaxws:inInterceptors>
>>> 			<bean
>>> class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
>>> 			<bean
>>> class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
>>> 				<property name="properties">
>>> 					<map>
>>> 						<entry key="action"
>>> value="UsernameToken"/>
>>> 						<entry
>>> key="passwordType" value="PasswordText"/>
>>> 						<entry
>>> key="passwordCallbackClass"
>>> value="demo.interceptors.AuthenticationCallbackHandler"/>
>>> 					</map>
>>> 				</property>
>>> 			</bean>
>>> 			<bean
>>> class="demo.interceptors.ValidateUserTokenInterceptor"/>
>>> 		</jaxws:inInterceptors>
>>> 
>>> 	</jaxws:endpoint>
>>> 
>>> AuthenticationCallbackHandler is very simple it just does the
>> following:
>>> 
>>> public void handle(Callback[] callbacks) throws IOException,
>>> UnsupportedCallbackException {
>>>                 WSPasswordCallback pc = (WSPasswordCallback)
>>> callbacks[0];
>>> 		
>>> 		if (pc.getIdentifer().equals("joe")) {
>>> 			pc.setPassword("password");
>>> 		}
>>> 	}
>>> 
>>> I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
>>> should
>>> Validate received token. 
>>> 
>>> public void handleMessage(Message message) throws Fault {
>>> 		boolean userTokenValidated = false;
>>> 
>>> 		logger.debug("Invoked - ValidateUserToken: " + message);
>>> 
>>> 		//logger.debug("messagePwd: " + message.get);
>>> 		Vector result = (Vector)
>>> message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
>>> 
>>> 		if (result==null) {
>>> 			throw new
>>> IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
>>> Property not found in MessageContext?!");
>>> 		}
>>> 
>>> 		for (int i = 0; i < result.size(); i++) {
>>> 			WSHandlerResult res = (WSHandlerResult)
>>> result.get(i);
>>> 			for (int j = 0; j < res.getResults().size();
>>> j++) {
>>> 				WSSecurityEngineResult secRes =
>>> (WSSecurityEngineResult)
>>> res.getResults().get(j);
>>> 				int action = secRes.getAction();
>>> 				logger.debug("Checking: " + secRes);
>>> 				// USER TOKEN
>>> 				if ((action & WSConstants.UT) > 0) {
>>> 					WSUsernameTokenPrincipal
>>> principal = (WSUsernameTokenPrincipal)
>>> secRes.getPrincipal();
>>> 					logger.debug("name=" +
>>> principal.getName());
>>> 					logger.debug("password=" +
>>> principal.getPassword());
>>> 					logger.debug("passwordType=" +
>>> principal.getPasswordType());
>>> 					logger.debug("createdTime=" +
>>> principal.getCreatedTime());
>>> 
>>> 					if (principal.getPassword() ==
>>> null) {
>>> 						throw new
>>> RuntimeException("Invalid Security Header");
>>> 					} else {
>>>                                                 // NOW COMPARE
>> PASSWORDS
>>> -
>>> HOW????
>>> 						userTokenValidated =
>>> true;
>>> 					}
>>> 				}
>>> 			}
>>> 		}
>>> 		if (!userTokenValidated) {
>>> 			throw new RuntimeException("Security processing
>>> failed");
>>> 		}
>>> 	}
>>> 
>>> So far i was able to read information from WSSE:Security header - ie.
>>> username and pwd supplied by the Client. But i do not know how to
>>> address
>>> the password value supplied by AuthenticationCallbackHandler inside
>> this
>>> interceptor??
>>> 
>>> 2) Second question: how to properly configure interceptors on client
>>> using
>>> spring?
>>> 
>>> To test the service i wrote simple HelloClient:
>>> 
>>> public static void main(String[] args) {
>>> 
>>> 		ApplicationContext context = new
>>> ClassPathXmlApplicationContext("/clientAppContext.xml");
>>> 		HelloWorld client = (HelloWorld)
>>> context.getBean("client");
>>> 		System.out.println("Invoking service...");
>>> 		String text = client.sayHi("Domagoj");
>>> 		System.out.println("Response=: " + text);
>>> 	}
>>> 
>>> This is my clientAppContext.xml:
>>> 
>>> <bean id="client" class="demo.spring.HelloWorld" 
>>> factory-bean="clientFactory" factory-method="create"/>
>>> 
>>> 	<bean id="clientFactory"
>>> class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
>>> 	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
>>> 	  <property name="address"
>>> value="http://localhost:8080/SoaLab/HelloWorld"/>
>>> 	  <property name="outInterceptors">
>>> 			<list>
>>> 				<bean
>>> class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
>>> 				<bean
>>> class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
>>> 					<property name="properties">
>>> 						<map>
>>> 							<entry
>>> key="action" value="UsernameToken"/>
>>> 							<entry
>>> key="user" value="joe"/>
>>> 							<entry
>>> key="passwordType" value="PasswordText"/>
>>> 							<entry
>>> key="passwordCallbackClass"
>>> value="demo.interceptors.ClientPasswordCallback"/>
>>> 						</map>
>>> 					</property>
>>> 				</bean>
>>> 			</list>
>>> 		</property>
>>> 	</bean>
>>> 
>>> The problem i have is that Response i receive from HelloWorld service
>> is
>>> null??
>>> If i comment interceptors on both client and server side it all works
>>> fine.
>>> 
>>> Any suggestions?
>>> 
>>> Thx in advance....
>>> 
>>> 
>>> -- 
>>> View this message in context:
>>> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
>>> Sent from the cxf-user mailing list archive at Nabble.com.
>>> 
>>> ----------------------------
>>> IONA Technologies PLC (registered in Ireland)
>>> Registered Number: 171387
>>> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
>> Ireland
>>> 
>>> 
>> 
>> -- 
>> View this message in context:
>> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12366436
>> Sent from the cxf-user mailing list archive at Nabble.com.
>> 
>> ----------------------------
>> IONA Technologies PLC (registered in Ireland)
>> Registered Number: 171387
>> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
> Ireland
>> 
>> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12369765
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland
> 
> 

-- 
View this message in context: http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12407581
Sent from the cxf-user mailing list archive at Nabble.com.


RE: WS-Security and CXF

Posted by "O hEigeartaigh, Colm" <Co...@iona.com>.
Hi,

Some comments on your comments...

> So, first, what do you think would be proper behavioure of
CallbackHandler
> in case of authentication failure?

In the case of authentication failure, I guess you could throw a
org.apache.ws.security.WSSecurityException in the handle method of your 
CallbackHandler implementation. WSSecurityException extends 
java.rmi.RemoteException, which in turn extends java.io.IOException,
which is explicitly thrown by the handle method, and caught accordingly
in UsernameTokenProcessor.

However, the fact that WSSecurityExceptions aren't explicitly caught and
thrown on in UsernameTokenProcessor is a bug which should be raised with
WSS4J. Ultimately, the logic for handling a plaintext password derived
from an incoming UsernameToken needs to be rewritten to separate the
password callback mechanism from the processing of the password, as is
done for the digested case.

> Furthermore, UsernameTokenProcessor converts both of this Exceptions
to
> WSSecurityException with "noPassword" message which is actually not

> correct information, maybe wrong password was supplied, or
CallbackHandler > could not contact LDAP to chek for password so it
throwed IOException 
> which was then converted to also WSSecurityException with noPassword 
> label?

This will be fixed by the change that I proposed above. However, note
that 
"noPassword" is defined in errors.properties as
"noPassword=WSSecurityEngine: Callback supplied no password for: {0}",
so it's not totally cryptic.

> Second, i would like to know is there a way how one can configure
> CallbackHandler through Spring application context, and then just pass
> reference to it to the WSS4jInInterceptor instead of a class name.
This is
> especially of handy  if CallbackHandler needs to connect to some
external
> storage such as LDAP or DB to retrive pwd.

You can pass a reference to a callback handler in code with something
like;

Map<String, Object> properties = ...
properties.put(WSHandlerConstants.PW_CALLBACK_REF,
callbackHandlerObject);
WSS4JInInterceptor inHandler = new WSS4JInInterceptor(properties);

Doing this through spring could be tricky though...

Colm.


-----Original Message-----
From: dmadunic [mailto:domagoj.madunic@gmail.com] 
Sent: 28 August 2007 16:06
To: cxf-user@incubator.apache.org
Subject: RE: WS-Security and CXF


Hi Colm,
thx for pointing me to the right direction - although i was attempting
to
avoid looking at the sources at any cost, especially since this seemed
to me
as quite simple task. Anyway, after looking at sources for wss4j and cxf
I
now begin to grasp how and what should be done, but still have some
questions - which are actually more of a comment.

As far as i can see handling of differnt type of security actions is
done by
various classes in wss4j which all implement following interface:

org.apache.ws.security.processor.Processor

one of those classes is also UsernameTokenProcessor, which follows the
behaviour You described in your posts, ie. it will handle everything
only if
supplied pwd is hashed otherwise (if for example pwd is Plain text) it
expects for CallbackHandler to handle things.
Apart from the fact that this is bad design, since no clear division of
roles is established, it is not clear what should Callback class do if
passwords do not match, or if validation fails for some other reasons??!

Java code that handles this check in UsernameTokenProcessor is as
follows:

WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
                    pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
            callbacks[0] = pwCb;
            try {
                cb.handle(callbacks);
            } catch (IOException e) {
                throw new
WSSecurityException(WSSecurityException.FAILURE,
                        "noPassword", new Object[]{user});
            } catch (UnsupportedCallbackException e) {
                throw new
WSSecurityException(WSSecurityException.FAILURE,
                        "noPassword", new Object[]{user});
            }

So CallbackHandler has only options of throwing IOException or
UnsupportedCallbackException, which is neither appropritate exception
for
case when authentication failes due to the wrong password.
Furthermore, UsernameTokenProcessor converts both of this Exceptions to
WSSecurityException with "noPassword" message which is actually not
correct
information, maybe wrong password was supplied, or CallbackHandler could
not
contact LDAP to chek for password so it throwed IOException which was
then
converted to also WSSecurityException with noPassword label?

So, first, what do you think would be proper behavioure of
CallbackHandler
in case of authentication failure?
Second, i would like to know is there a way how one can configure
CallbackHandler through Spring application context, and then just pass
reference to it to the WSS4jInInterceptor instead of a class name. This
is
especially of handy  if CallbackHandler needs to connect to some
external
storage such as LDAP or DB to retrive pwd.

thx

O hEigeartaigh, Colm wrote:
> 
> 
> WSS4JInInterceptor is an interceptor that processes the WS-Security
> components of an inbound SOAP message. So for example, in your case
you
> need to configure it to process UsernameTokens, and pass it a
> CallbackHandler implementation so that it knows how to handle the
> password validation. 
> 
> Whether it is a "preparatory interceptor" or not depends on your
> requirements. You may, for example, want to use the WSS4JInInterceptor
> to validate the UsernameToken, and then use the username/password for
> other purposes in another interceptor. But this use case is outside
the
> scope of WS-Security, and hence WSS4JInInterceptor does not handle it.
> 
> Your best bet in understanding how WSS4JInInterceptor works is to
peruse
> the code + look at the unit and system tests. I agree the
documentation
> is substandard, I might add improving it to my to-do list ;-)
> 
> Colm.
> 
> 
> -----Original Message-----
> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
> Sent: 28 August 2007 12:43
> To: cxf-user@incubator.apache.org
> Subject: RE: WS-Security and CXF
> 
> 
> Thx a lot Colm,
> actually i think my problem was that I totally do not understand what
> does
> WSS4JInInterceptor do or is supposed to do?
> 
> Javadoc for the method handleMessage says only this:
> 
> Description copied from interface: Interceptor
>     Intercepts a message. Interceptors need NOT invoke handleMessage
or
> handleFault on the next interceptor - the interceptor chain will take
> care
> of this.
> 
> which is quite useless ;-(
> 
> After seeing examples in CXF User guide i assumed that it was kind of
> preparatory interceptor - one that will prepare context for further
> processing - hence the need to configure it with the
> PasswordCallbackHandler, but it seems it is not so?
> It would be nice if someone clarified the functionality of this
> interceptor
> and what are all of his configuration options. Informatio on
> http://cwiki.apache.org/CXF20DOC/ws-security.html is very basic and
> lacking
> any explanations....
> 
> thx
> 
> 
> O hEigeartaigh, Colm wrote:
>> 
>> Hi,
>> 
>> To answer your first question: To fully understand the semantics of
>> processing an inbound UsernameToken, you need to examine the
>> implementation of
>> org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
>> Basically, the implementation is as follows:
>> 
>> a) Digested Password: Get the original password from the
> CallbackHandler
>> implementation, process it accordingly and compare to the received
>> digested password.
>> b) Any other Password Type: Delegate all validation to the
>> CallbackHandler implementation.
>> 
>> So how you implement your CallbackHandler implementation depends on
> your
>> requirements. At the moment your implementation essentially does no
>> processing of the password. 
>> 
>> So to summarise, any code you have for comparing the password etc.
>> should be implemented in AuthenticationCallbackHandler, rather than
in
>> your ValidateUserTokenInterceptor.
>> 
>> Colm.
>> 
>> -----Original Message-----
>> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
>> Sent: 28 August 2007 11:14
>> To: cxf-user@incubator.apache.org
>> Subject: WS-Security and CXF
>> 
>> 
>> Hi all,
>> i have two questions concerning how to implement WS-Security with
CXF.
>> 
>> 1) First question: how on the server side to read CallbackHandler
>> supplied
>> password?
>> 
>> Followoing instructions on CXF homesite and from several articles, I
>> have
>> created simple HelloWorldService and attached to it following
>> interceptors:
>> 
>> 	<jaxws:endpoint  id="helloWorld"
>> implementor="demo.spring.HelloWorldImpl"
>> address="/HelloWorld" >
>> 		<jaxws:inInterceptors>
>> 			<bean
>> class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
>> 			<bean
>> class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
>> 				<property name="properties">
>> 					<map>
>> 						<entry key="action"
>> value="UsernameToken"/>
>> 						<entry
>> key="passwordType" value="PasswordText"/>
>> 						<entry
>> key="passwordCallbackClass"
>> value="demo.interceptors.AuthenticationCallbackHandler"/>
>> 					</map>
>> 				</property>
>> 			</bean>
>> 			<bean
>> class="demo.interceptors.ValidateUserTokenInterceptor"/>
>> 		</jaxws:inInterceptors>
>> 
>> 	</jaxws:endpoint>
>> 
>> AuthenticationCallbackHandler is very simple it just does the
> following:
>> 
>> public void handle(Callback[] callbacks) throws IOException,
>> UnsupportedCallbackException {
>>                 WSPasswordCallback pc = (WSPasswordCallback)
>> callbacks[0];
>> 		
>> 		if (pc.getIdentifer().equals("joe")) {
>> 			pc.setPassword("password");
>> 		}
>> 	}
>> 
>> I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
>> should
>> Validate received token. 
>> 
>> public void handleMessage(Message message) throws Fault {
>> 		boolean userTokenValidated = false;
>> 
>> 		logger.debug("Invoked - ValidateUserToken: " + message);
>> 
>> 		//logger.debug("messagePwd: " + message.get);
>> 		Vector result = (Vector)
>> message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
>> 
>> 		if (result==null) {
>> 			throw new
>> IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
>> Property not found in MessageContext?!");
>> 		}
>> 
>> 		for (int i = 0; i < result.size(); i++) {
>> 			WSHandlerResult res = (WSHandlerResult)
>> result.get(i);
>> 			for (int j = 0; j < res.getResults().size();
>> j++) {
>> 				WSSecurityEngineResult secRes =
>> (WSSecurityEngineResult)
>> res.getResults().get(j);
>> 				int action = secRes.getAction();
>> 				logger.debug("Checking: " + secRes);
>> 				// USER TOKEN
>> 				if ((action & WSConstants.UT) > 0) {
>> 					WSUsernameTokenPrincipal
>> principal = (WSUsernameTokenPrincipal)
>> secRes.getPrincipal();
>> 					logger.debug("name=" +
>> principal.getName());
>> 					logger.debug("password=" +
>> principal.getPassword());
>> 					logger.debug("passwordType=" +
>> principal.getPasswordType());
>> 					logger.debug("createdTime=" +
>> principal.getCreatedTime());
>> 
>> 					if (principal.getPassword() ==
>> null) {
>> 						throw new
>> RuntimeException("Invalid Security Header");
>> 					} else {
>>                                                 // NOW COMPARE
> PASSWORDS
>> -
>> HOW????
>> 						userTokenValidated =
>> true;
>> 					}
>> 				}
>> 			}
>> 		}
>> 		if (!userTokenValidated) {
>> 			throw new RuntimeException("Security processing
>> failed");
>> 		}
>> 	}
>> 
>> So far i was able to read information from WSSE:Security header - ie.
>> username and pwd supplied by the Client. But i do not know how to
>> address
>> the password value supplied by AuthenticationCallbackHandler inside
> this
>> interceptor??
>> 
>> 2) Second question: how to properly configure interceptors on client
>> using
>> spring?
>> 
>> To test the service i wrote simple HelloClient:
>> 
>> public static void main(String[] args) {
>> 
>> 		ApplicationContext context = new
>> ClassPathXmlApplicationContext("/clientAppContext.xml");
>> 		HelloWorld client = (HelloWorld)
>> context.getBean("client");
>> 		System.out.println("Invoking service...");
>> 		String text = client.sayHi("Domagoj");
>> 		System.out.println("Response=: " + text);
>> 	}
>> 
>> This is my clientAppContext.xml:
>> 
>> <bean id="client" class="demo.spring.HelloWorld" 
>> factory-bean="clientFactory" factory-method="create"/>
>> 
>> 	<bean id="clientFactory"
>> class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
>> 	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
>> 	  <property name="address"
>> value="http://localhost:8080/SoaLab/HelloWorld"/>
>> 	  <property name="outInterceptors">
>> 			<list>
>> 				<bean
>> class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
>> 				<bean
>> class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
>> 					<property name="properties">
>> 						<map>
>> 							<entry
>> key="action" value="UsernameToken"/>
>> 							<entry
>> key="user" value="joe"/>
>> 							<entry
>> key="passwordType" value="PasswordText"/>
>> 							<entry
>> key="passwordCallbackClass"
>> value="demo.interceptors.ClientPasswordCallback"/>
>> 						</map>
>> 					</property>
>> 				</bean>
>> 			</list>
>> 		</property>
>> 	</bean>
>> 
>> The problem i have is that Response i receive from HelloWorld service
> is
>> null??
>> If i comment interceptors on both client and server side it all works
>> fine.
>> 
>> Any suggestions?
>> 
>> Thx in advance....
>> 
>> 
>> -- 
>> View this message in context:
>> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
>> Sent from the cxf-user mailing list archive at Nabble.com.
>> 
>> ----------------------------
>> IONA Technologies PLC (registered in Ireland)
>> Registered Number: 171387
>> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
> Ireland
>> 
>> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12366436
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
Ireland
> 
> 

-- 
View this message in context:
http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12369765
Sent from the cxf-user mailing list archive at Nabble.com.

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland

RE: WS-Security and CXF

Posted by dmadunic <do...@gmail.com>.
Hi Colm,
thx for pointing me to the right direction - although i was attempting to
avoid looking at the sources at any cost, especially since this seemed to me
as quite simple task. Anyway, after looking at sources for wss4j and cxf I
now begin to grasp how and what should be done, but still have some
questions - which are actually more of a comment.

As far as i can see handling of differnt type of security actions is done by
various classes in wss4j which all implement following interface:

org.apache.ws.security.processor.Processor

one of those classes is also UsernameTokenProcessor, which follows the
behaviour You described in your posts, ie. it will handle everything only if
supplied pwd is hashed otherwise (if for example pwd is Plain text) it
expects for CallbackHandler to handle things.
Apart from the fact that this is bad design, since no clear division of
roles is established, it is not clear what should Callback class do if
passwords do not match, or if validation fails for some other reasons??!

Java code that handles this check in UsernameTokenProcessor is as follows:

WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
                    pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
            callbacks[0] = pwCb;
            try {
                cb.handle(callbacks);
            } catch (IOException e) {
                throw new WSSecurityException(WSSecurityException.FAILURE,
                        "noPassword", new Object[]{user});
            } catch (UnsupportedCallbackException e) {
                throw new WSSecurityException(WSSecurityException.FAILURE,
                        "noPassword", new Object[]{user});
            }

So CallbackHandler has only options of throwing IOException or
UnsupportedCallbackException, which is neither appropritate exception for
case when authentication failes due to the wrong password.
Furthermore, UsernameTokenProcessor converts both of this Exceptions to
WSSecurityException with "noPassword" message which is actually not correct
information, maybe wrong password was supplied, or CallbackHandler could not
contact LDAP to chek for password so it throwed IOException which was then
converted to also WSSecurityException with noPassword label?

So, first, what do you think would be proper behavioure of CallbackHandler
in case of authentication failure?
Second, i would like to know is there a way how one can configure
CallbackHandler through Spring application context, and then just pass
reference to it to the WSS4jInInterceptor instead of a class name. This is
especially of handy  if CallbackHandler needs to connect to some external
storage such as LDAP or DB to retrive pwd.

thx

O hEigeartaigh, Colm wrote:
> 
> 
> WSS4JInInterceptor is an interceptor that processes the WS-Security
> components of an inbound SOAP message. So for example, in your case you
> need to configure it to process UsernameTokens, and pass it a
> CallbackHandler implementation so that it knows how to handle the
> password validation. 
> 
> Whether it is a "preparatory interceptor" or not depends on your
> requirements. You may, for example, want to use the WSS4JInInterceptor
> to validate the UsernameToken, and then use the username/password for
> other purposes in another interceptor. But this use case is outside the
> scope of WS-Security, and hence WSS4JInInterceptor does not handle it.
> 
> Your best bet in understanding how WSS4JInInterceptor works is to peruse
> the code + look at the unit and system tests. I agree the documentation
> is substandard, I might add improving it to my to-do list ;-)
> 
> Colm.
> 
> 
> -----Original Message-----
> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
> Sent: 28 August 2007 12:43
> To: cxf-user@incubator.apache.org
> Subject: RE: WS-Security and CXF
> 
> 
> Thx a lot Colm,
> actually i think my problem was that I totally do not understand what
> does
> WSS4JInInterceptor do or is supposed to do?
> 
> Javadoc for the method handleMessage says only this:
> 
> Description copied from interface: Interceptor
>     Intercepts a message. Interceptors need NOT invoke handleMessage or
> handleFault on the next interceptor - the interceptor chain will take
> care
> of this.
> 
> which is quite useless ;-(
> 
> After seeing examples in CXF User guide i assumed that it was kind of
> preparatory interceptor - one that will prepare context for further
> processing - hence the need to configure it with the
> PasswordCallbackHandler, but it seems it is not so?
> It would be nice if someone clarified the functionality of this
> interceptor
> and what are all of his configuration options. Informatio on
> http://cwiki.apache.org/CXF20DOC/ws-security.html is very basic and
> lacking
> any explanations....
> 
> thx
> 
> 
> O hEigeartaigh, Colm wrote:
>> 
>> Hi,
>> 
>> To answer your first question: To fully understand the semantics of
>> processing an inbound UsernameToken, you need to examine the
>> implementation of
>> org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
>> Basically, the implementation is as follows:
>> 
>> a) Digested Password: Get the original password from the
> CallbackHandler
>> implementation, process it accordingly and compare to the received
>> digested password.
>> b) Any other Password Type: Delegate all validation to the
>> CallbackHandler implementation.
>> 
>> So how you implement your CallbackHandler implementation depends on
> your
>> requirements. At the moment your implementation essentially does no
>> processing of the password. 
>> 
>> So to summarise, any code you have for comparing the password etc.
>> should be implemented in AuthenticationCallbackHandler, rather than in
>> your ValidateUserTokenInterceptor.
>> 
>> Colm.
>> 
>> -----Original Message-----
>> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
>> Sent: 28 August 2007 11:14
>> To: cxf-user@incubator.apache.org
>> Subject: WS-Security and CXF
>> 
>> 
>> Hi all,
>> i have two questions concerning how to implement WS-Security with CXF.
>> 
>> 1) First question: how on the server side to read CallbackHandler
>> supplied
>> password?
>> 
>> Followoing instructions on CXF homesite and from several articles, I
>> have
>> created simple HelloWorldService and attached to it following
>> interceptors:
>> 
>> 	<jaxws:endpoint  id="helloWorld"
>> implementor="demo.spring.HelloWorldImpl"
>> address="/HelloWorld" >
>> 		<jaxws:inInterceptors>
>> 			<bean
>> class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
>> 			<bean
>> class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
>> 				<property name="properties">
>> 					<map>
>> 						<entry key="action"
>> value="UsernameToken"/>
>> 						<entry
>> key="passwordType" value="PasswordText"/>
>> 						<entry
>> key="passwordCallbackClass"
>> value="demo.interceptors.AuthenticationCallbackHandler"/>
>> 					</map>
>> 				</property>
>> 			</bean>
>> 			<bean
>> class="demo.interceptors.ValidateUserTokenInterceptor"/>
>> 		</jaxws:inInterceptors>
>> 
>> 	</jaxws:endpoint>
>> 
>> AuthenticationCallbackHandler is very simple it just does the
> following:
>> 
>> public void handle(Callback[] callbacks) throws IOException,
>> UnsupportedCallbackException {
>>                 WSPasswordCallback pc = (WSPasswordCallback)
>> callbacks[0];
>> 		
>> 		if (pc.getIdentifer().equals("joe")) {
>> 			pc.setPassword("password");
>> 		}
>> 	}
>> 
>> I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
>> should
>> Validate received token. 
>> 
>> public void handleMessage(Message message) throws Fault {
>> 		boolean userTokenValidated = false;
>> 
>> 		logger.debug("Invoked - ValidateUserToken: " + message);
>> 
>> 		//logger.debug("messagePwd: " + message.get);
>> 		Vector result = (Vector)
>> message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
>> 
>> 		if (result==null) {
>> 			throw new
>> IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
>> Property not found in MessageContext?!");
>> 		}
>> 
>> 		for (int i = 0; i < result.size(); i++) {
>> 			WSHandlerResult res = (WSHandlerResult)
>> result.get(i);
>> 			for (int j = 0; j < res.getResults().size();
>> j++) {
>> 				WSSecurityEngineResult secRes =
>> (WSSecurityEngineResult)
>> res.getResults().get(j);
>> 				int action = secRes.getAction();
>> 				logger.debug("Checking: " + secRes);
>> 				// USER TOKEN
>> 				if ((action & WSConstants.UT) > 0) {
>> 					WSUsernameTokenPrincipal
>> principal = (WSUsernameTokenPrincipal)
>> secRes.getPrincipal();
>> 					logger.debug("name=" +
>> principal.getName());
>> 					logger.debug("password=" +
>> principal.getPassword());
>> 					logger.debug("passwordType=" +
>> principal.getPasswordType());
>> 					logger.debug("createdTime=" +
>> principal.getCreatedTime());
>> 
>> 					if (principal.getPassword() ==
>> null) {
>> 						throw new
>> RuntimeException("Invalid Security Header");
>> 					} else {
>>                                                 // NOW COMPARE
> PASSWORDS
>> -
>> HOW????
>> 						userTokenValidated =
>> true;
>> 					}
>> 				}
>> 			}
>> 		}
>> 		if (!userTokenValidated) {
>> 			throw new RuntimeException("Security processing
>> failed");
>> 		}
>> 	}
>> 
>> So far i was able to read information from WSSE:Security header - ie.
>> username and pwd supplied by the Client. But i do not know how to
>> address
>> the password value supplied by AuthenticationCallbackHandler inside
> this
>> interceptor??
>> 
>> 2) Second question: how to properly configure interceptors on client
>> using
>> spring?
>> 
>> To test the service i wrote simple HelloClient:
>> 
>> public static void main(String[] args) {
>> 
>> 		ApplicationContext context = new
>> ClassPathXmlApplicationContext("/clientAppContext.xml");
>> 		HelloWorld client = (HelloWorld)
>> context.getBean("client");
>> 		System.out.println("Invoking service...");
>> 		String text = client.sayHi("Domagoj");
>> 		System.out.println("Response=: " + text);
>> 	}
>> 
>> This is my clientAppContext.xml:
>> 
>> <bean id="client" class="demo.spring.HelloWorld" 
>> factory-bean="clientFactory" factory-method="create"/>
>> 
>> 	<bean id="clientFactory"
>> class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
>> 	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
>> 	  <property name="address"
>> value="http://localhost:8080/SoaLab/HelloWorld"/>
>> 	  <property name="outInterceptors">
>> 			<list>
>> 				<bean
>> class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
>> 				<bean
>> class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
>> 					<property name="properties">
>> 						<map>
>> 							<entry
>> key="action" value="UsernameToken"/>
>> 							<entry
>> key="user" value="joe"/>
>> 							<entry
>> key="passwordType" value="PasswordText"/>
>> 							<entry
>> key="passwordCallbackClass"
>> value="demo.interceptors.ClientPasswordCallback"/>
>> 						</map>
>> 					</property>
>> 				</bean>
>> 			</list>
>> 		</property>
>> 	</bean>
>> 
>> The problem i have is that Response i receive from HelloWorld service
> is
>> null??
>> If i comment interceptors on both client and server side it all works
>> fine.
>> 
>> Any suggestions?
>> 
>> Thx in advance....
>> 
>> 
>> -- 
>> View this message in context:
>> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
>> Sent from the cxf-user mailing list archive at Nabble.com.
>> 
>> ----------------------------
>> IONA Technologies PLC (registered in Ireland)
>> Registered Number: 171387
>> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
> Ireland
>> 
>> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12366436
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland
> 
> 

-- 
View this message in context: http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12369765
Sent from the cxf-user mailing list archive at Nabble.com.


RE: WS-Security and CXF

Posted by "O hEigeartaigh, Colm" <Co...@iona.com>.
WSS4JInInterceptor is an interceptor that processes the WS-Security
components of an inbound SOAP message. So for example, in your case you
need to configure it to process UsernameTokens, and pass it a
CallbackHandler implementation so that it knows how to handle the
password validation. 

Whether it is a "preparatory interceptor" or not depends on your
requirements. You may, for example, want to use the WSS4JInInterceptor
to validate the UsernameToken, and then use the username/password for
other purposes in another interceptor. But this use case is outside the
scope of WS-Security, and hence WSS4JInInterceptor does not handle it.

Your best bet in understanding how WSS4JInInterceptor works is to peruse
the code + look at the unit and system tests. I agree the documentation
is substandard, I might add improving it to my to-do list ;-)

Colm.


-----Original Message-----
From: dmadunic [mailto:domagoj.madunic@gmail.com] 
Sent: 28 August 2007 12:43
To: cxf-user@incubator.apache.org
Subject: RE: WS-Security and CXF


Thx a lot Colm,
actually i think my problem was that I totally do not understand what
does
WSS4JInInterceptor do or is supposed to do?

Javadoc for the method handleMessage says only this:

Description copied from interface: Interceptor
    Intercepts a message. Interceptors need NOT invoke handleMessage or
handleFault on the next interceptor - the interceptor chain will take
care
of this.

which is quite useless ;-(

After seeing examples in CXF User guide i assumed that it was kind of
preparatory interceptor - one that will prepare context for further
processing - hence the need to configure it with the
PasswordCallbackHandler, but it seems it is not so?
It would be nice if someone clarified the functionality of this
interceptor
and what are all of his configuration options. Informatio on
http://cwiki.apache.org/CXF20DOC/ws-security.html is very basic and
lacking
any explanations....

thx


O hEigeartaigh, Colm wrote:
> 
> Hi,
> 
> To answer your first question: To fully understand the semantics of
> processing an inbound UsernameToken, you need to examine the
> implementation of
> org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
> Basically, the implementation is as follows:
> 
> a) Digested Password: Get the original password from the
CallbackHandler
> implementation, process it accordingly and compare to the received
> digested password.
> b) Any other Password Type: Delegate all validation to the
> CallbackHandler implementation.
> 
> So how you implement your CallbackHandler implementation depends on
your
> requirements. At the moment your implementation essentially does no
> processing of the password. 
> 
> So to summarise, any code you have for comparing the password etc.
> should be implemented in AuthenticationCallbackHandler, rather than in
> your ValidateUserTokenInterceptor.
> 
> Colm.
> 
> -----Original Message-----
> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
> Sent: 28 August 2007 11:14
> To: cxf-user@incubator.apache.org
> Subject: WS-Security and CXF
> 
> 
> Hi all,
> i have two questions concerning how to implement WS-Security with CXF.
> 
> 1) First question: how on the server side to read CallbackHandler
> supplied
> password?
> 
> Followoing instructions on CXF homesite and from several articles, I
> have
> created simple HelloWorldService and attached to it following
> interceptors:
> 
> 	<jaxws:endpoint  id="helloWorld"
> implementor="demo.spring.HelloWorldImpl"
> address="/HelloWorld" >
> 		<jaxws:inInterceptors>
> 			<bean
> class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
> 			<bean
> class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
> 				<property name="properties">
> 					<map>
> 						<entry key="action"
> value="UsernameToken"/>
> 						<entry
> key="passwordType" value="PasswordText"/>
> 						<entry
> key="passwordCallbackClass"
> value="demo.interceptors.AuthenticationCallbackHandler"/>
> 					</map>
> 				</property>
> 			</bean>
> 			<bean
> class="demo.interceptors.ValidateUserTokenInterceptor"/>
> 		</jaxws:inInterceptors>
> 
> 	</jaxws:endpoint>
> 
> AuthenticationCallbackHandler is very simple it just does the
following:
> 
> public void handle(Callback[] callbacks) throws IOException,
> UnsupportedCallbackException {
>                 WSPasswordCallback pc = (WSPasswordCallback)
> callbacks[0];
> 		
> 		if (pc.getIdentifer().equals("joe")) {
> 			pc.setPassword("password");
> 		}
> 	}
> 
> I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
> should
> Validate received token. 
> 
> public void handleMessage(Message message) throws Fault {
> 		boolean userTokenValidated = false;
> 
> 		logger.debug("Invoked - ValidateUserToken: " + message);
> 
> 		//logger.debug("messagePwd: " + message.get);
> 		Vector result = (Vector)
> message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
> 
> 		if (result==null) {
> 			throw new
> IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
> Property not found in MessageContext?!");
> 		}
> 
> 		for (int i = 0; i < result.size(); i++) {
> 			WSHandlerResult res = (WSHandlerResult)
> result.get(i);
> 			for (int j = 0; j < res.getResults().size();
> j++) {
> 				WSSecurityEngineResult secRes =
> (WSSecurityEngineResult)
> res.getResults().get(j);
> 				int action = secRes.getAction();
> 				logger.debug("Checking: " + secRes);
> 				// USER TOKEN
> 				if ((action & WSConstants.UT) > 0) {
> 					WSUsernameTokenPrincipal
> principal = (WSUsernameTokenPrincipal)
> secRes.getPrincipal();
> 					logger.debug("name=" +
> principal.getName());
> 					logger.debug("password=" +
> principal.getPassword());
> 					logger.debug("passwordType=" +
> principal.getPasswordType());
> 					logger.debug("createdTime=" +
> principal.getCreatedTime());
> 
> 					if (principal.getPassword() ==
> null) {
> 						throw new
> RuntimeException("Invalid Security Header");
> 					} else {
>                                                 // NOW COMPARE
PASSWORDS
> -
> HOW????
> 						userTokenValidated =
> true;
> 					}
> 				}
> 			}
> 		}
> 		if (!userTokenValidated) {
> 			throw new RuntimeException("Security processing
> failed");
> 		}
> 	}
> 
> So far i was able to read information from WSSE:Security header - ie.
> username and pwd supplied by the Client. But i do not know how to
> address
> the password value supplied by AuthenticationCallbackHandler inside
this
> interceptor??
> 
> 2) Second question: how to properly configure interceptors on client
> using
> spring?
> 
> To test the service i wrote simple HelloClient:
> 
> public static void main(String[] args) {
> 
> 		ApplicationContext context = new
> ClassPathXmlApplicationContext("/clientAppContext.xml");
> 		HelloWorld client = (HelloWorld)
> context.getBean("client");
> 		System.out.println("Invoking service...");
> 		String text = client.sayHi("Domagoj");
> 		System.out.println("Response=: " + text);
> 	}
> 
> This is my clientAppContext.xml:
> 
> <bean id="client" class="demo.spring.HelloWorld" 
> factory-bean="clientFactory" factory-method="create"/>
> 
> 	<bean id="clientFactory"
> class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
> 	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
> 	  <property name="address"
> value="http://localhost:8080/SoaLab/HelloWorld"/>
> 	  <property name="outInterceptors">
> 			<list>
> 				<bean
> class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
> 				<bean
> class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
> 					<property name="properties">
> 						<map>
> 							<entry
> key="action" value="UsernameToken"/>
> 							<entry
> key="user" value="joe"/>
> 							<entry
> key="passwordType" value="PasswordText"/>
> 							<entry
> key="passwordCallbackClass"
> value="demo.interceptors.ClientPasswordCallback"/>
> 						</map>
> 					</property>
> 				</bean>
> 			</list>
> 		</property>
> 	</bean>
> 
> The problem i have is that Response i receive from HelloWorld service
is
> null??
> If i comment interceptors on both client and server side it all works
> fine.
> 
> Any suggestions?
> 
> Thx in advance....
> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
Ireland
> 
> 

-- 
View this message in context:
http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12366436
Sent from the cxf-user mailing list archive at Nabble.com.

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland

RE: WS-Security and CXF

Posted by dmadunic <do...@gmail.com>.
Thx a lot Colm,
actually i think my problem was that I totally do not understand what does
WSS4JInInterceptor do or is supposed to do?

Javadoc for the method handleMessage says only this:

Description copied from interface: Interceptor
    Intercepts a message. Interceptors need NOT invoke handleMessage or
handleFault on the next interceptor - the interceptor chain will take care
of this.

which is quite useless ;-(

After seeing examples in CXF User guide i assumed that it was kind of
preparatory interceptor - one that will prepare context for further
processing - hence the need to configure it with the
PasswordCallbackHandler, but it seems it is not so?
It would be nice if someone clarified the functionality of this interceptor
and what are all of his configuration options. Informatio on
http://cwiki.apache.org/CXF20DOC/ws-security.html is very basic and lacking
any explanations....

thx


O hEigeartaigh, Colm wrote:
> 
> Hi,
> 
> To answer your first question: To fully understand the semantics of
> processing an inbound UsernameToken, you need to examine the
> implementation of
> org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
> Basically, the implementation is as follows:
> 
> a) Digested Password: Get the original password from the CallbackHandler
> implementation, process it accordingly and compare to the received
> digested password.
> b) Any other Password Type: Delegate all validation to the
> CallbackHandler implementation.
> 
> So how you implement your CallbackHandler implementation depends on your
> requirements. At the moment your implementation essentially does no
> processing of the password. 
> 
> So to summarise, any code you have for comparing the password etc.
> should be implemented in AuthenticationCallbackHandler, rather than in
> your ValidateUserTokenInterceptor.
> 
> Colm.
> 
> -----Original Message-----
> From: dmadunic [mailto:domagoj.madunic@gmail.com] 
> Sent: 28 August 2007 11:14
> To: cxf-user@incubator.apache.org
> Subject: WS-Security and CXF
> 
> 
> Hi all,
> i have two questions concerning how to implement WS-Security with CXF.
> 
> 1) First question: how on the server side to read CallbackHandler
> supplied
> password?
> 
> Followoing instructions on CXF homesite and from several articles, I
> have
> created simple HelloWorldService and attached to it following
> interceptors:
> 
> 	<jaxws:endpoint  id="helloWorld"
> implementor="demo.spring.HelloWorldImpl"
> address="/HelloWorld" >
> 		<jaxws:inInterceptors>
> 			<bean
> class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
> 			<bean
> class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
> 				<property name="properties">
> 					<map>
> 						<entry key="action"
> value="UsernameToken"/>
> 						<entry
> key="passwordType" value="PasswordText"/>
> 						<entry
> key="passwordCallbackClass"
> value="demo.interceptors.AuthenticationCallbackHandler"/>
> 					</map>
> 				</property>
> 			</bean>
> 			<bean
> class="demo.interceptors.ValidateUserTokenInterceptor"/>
> 		</jaxws:inInterceptors>
> 
> 	</jaxws:endpoint>
> 
> AuthenticationCallbackHandler is very simple it just does the following:
> 
> public void handle(Callback[] callbacks) throws IOException,
> UnsupportedCallbackException {
>                 WSPasswordCallback pc = (WSPasswordCallback)
> callbacks[0];
> 		
> 		if (pc.getIdentifer().equals("joe")) {
> 			pc.setPassword("password");
> 		}
> 	}
> 
> I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
> should
> Validate received token. 
> 
> public void handleMessage(Message message) throws Fault {
> 		boolean userTokenValidated = false;
> 
> 		logger.debug("Invoked - ValidateUserToken: " + message);
> 
> 		//logger.debug("messagePwd: " + message.get);
> 		Vector result = (Vector)
> message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
> 
> 		if (result==null) {
> 			throw new
> IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
> Property not found in MessageContext?!");
> 		}
> 
> 		for (int i = 0; i < result.size(); i++) {
> 			WSHandlerResult res = (WSHandlerResult)
> result.get(i);
> 			for (int j = 0; j < res.getResults().size();
> j++) {
> 				WSSecurityEngineResult secRes =
> (WSSecurityEngineResult)
> res.getResults().get(j);
> 				int action = secRes.getAction();
> 				logger.debug("Checking: " + secRes);
> 				// USER TOKEN
> 				if ((action & WSConstants.UT) > 0) {
> 					WSUsernameTokenPrincipal
> principal = (WSUsernameTokenPrincipal)
> secRes.getPrincipal();
> 					logger.debug("name=" +
> principal.getName());
> 					logger.debug("password=" +
> principal.getPassword());
> 					logger.debug("passwordType=" +
> principal.getPasswordType());
> 					logger.debug("createdTime=" +
> principal.getCreatedTime());
> 
> 					if (principal.getPassword() ==
> null) {
> 						throw new
> RuntimeException("Invalid Security Header");
> 					} else {
>                                                 // NOW COMPARE PASSWORDS
> -
> HOW????
> 						userTokenValidated =
> true;
> 					}
> 				}
> 			}
> 		}
> 		if (!userTokenValidated) {
> 			throw new RuntimeException("Security processing
> failed");
> 		}
> 	}
> 
> So far i was able to read information from WSSE:Security header - ie.
> username and pwd supplied by the Client. But i do not know how to
> address
> the password value supplied by AuthenticationCallbackHandler inside this
> interceptor??
> 
> 2) Second question: how to properly configure interceptors on client
> using
> spring?
> 
> To test the service i wrote simple HelloClient:
> 
> public static void main(String[] args) {
> 
> 		ApplicationContext context = new
> ClassPathXmlApplicationContext("/clientAppContext.xml");
> 		HelloWorld client = (HelloWorld)
> context.getBean("client");
> 		System.out.println("Invoking service...");
> 		String text = client.sayHi("Domagoj");
> 		System.out.println("Response=: " + text);
> 	}
> 
> This is my clientAppContext.xml:
> 
> <bean id="client" class="demo.spring.HelloWorld" 
> factory-bean="clientFactory" factory-method="create"/>
> 
> 	<bean id="clientFactory"
> class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
> 	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
> 	  <property name="address"
> value="http://localhost:8080/SoaLab/HelloWorld"/>
> 	  <property name="outInterceptors">
> 			<list>
> 				<bean
> class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
> 				<bean
> class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
> 					<property name="properties">
> 						<map>
> 							<entry
> key="action" value="UsernameToken"/>
> 							<entry
> key="user" value="joe"/>
> 							<entry
> key="passwordType" value="PasswordText"/>
> 							<entry
> key="passwordCallbackClass"
> value="demo.interceptors.ClientPasswordCallback"/>
> 						</map>
> 					</property>
> 				</bean>
> 			</list>
> 		</property>
> 	</bean>
> 
> The problem i have is that Response i receive from HelloWorld service is
> null??
> If i comment interceptors on both client and server side it all works
> fine.
> 
> Any suggestions?
> 
> Thx in advance....
> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland
> 
> 

-- 
View this message in context: http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12366436
Sent from the cxf-user mailing list archive at Nabble.com.


RE: WS-Security and CXF

Posted by "O hEigeartaigh, Colm" <Co...@iona.com>.
Hi,

To answer your first question: To fully understand the semantics of
processing an inbound UsernameToken, you need to examine the
implementation of
org.apache.ws.security.processor.UsernameTokenProcessor in WSS4J.
Basically, the implementation is as follows:

a) Digested Password: Get the original password from the CallbackHandler
implementation, process it accordingly and compare to the received
digested password.
b) Any other Password Type: Delegate all validation to the
CallbackHandler implementation.

So how you implement your CallbackHandler implementation depends on your
requirements. At the moment your implementation essentially does no
processing of the password. 

So to summarise, any code you have for comparing the password etc.
should be implemented in AuthenticationCallbackHandler, rather than in
your ValidateUserTokenInterceptor.

Colm.

-----Original Message-----
From: dmadunic [mailto:domagoj.madunic@gmail.com] 
Sent: 28 August 2007 11:14
To: cxf-user@incubator.apache.org
Subject: WS-Security and CXF


Hi all,
i have two questions concerning how to implement WS-Security with CXF.

1) First question: how on the server side to read CallbackHandler
supplied
password?

Followoing instructions on CXF homesite and from several articles, I
have
created simple HelloWorldService and attached to it following
interceptors:

	<jaxws:endpoint  id="helloWorld"
implementor="demo.spring.HelloWorldImpl"
address="/HelloWorld" >
		<jaxws:inInterceptors>
			<bean
class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
			<bean
class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
				<property name="properties">
					<map>
						<entry key="action"
value="UsernameToken"/>
						<entry
key="passwordType" value="PasswordText"/>
						<entry
key="passwordCallbackClass"
value="demo.interceptors.AuthenticationCallbackHandler"/>
					</map>
				</property>
			</bean>
			<bean
class="demo.interceptors.ValidateUserTokenInterceptor"/>
		</jaxws:inInterceptors>

	</jaxws:endpoint>

AuthenticationCallbackHandler is very simple it just does the following:

public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
                WSPasswordCallback pc = (WSPasswordCallback)
callbacks[0];
		
		if (pc.getIdentifer().equals("joe")) {
			pc.setPassword("password");
		}
	}

I also wrote my demo.interceptors.ValidateUserTokenInterceptor which
should
Validate received token. 

public void handleMessage(Message message) throws Fault {
		boolean userTokenValidated = false;

		logger.debug("Invoked - ValidateUserToken: " + message);

		//logger.debug("messagePwd: " + message.get);
		Vector result = (Vector)
message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);

		if (result==null) {
			throw new
IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + "
Property not found in MessageContext?!");
		}

		for (int i = 0; i < result.size(); i++) {
			WSHandlerResult res = (WSHandlerResult)
result.get(i);
			for (int j = 0; j < res.getResults().size();
j++) {
				WSSecurityEngineResult secRes =
(WSSecurityEngineResult)
res.getResults().get(j);
				int action = secRes.getAction();
				logger.debug("Checking: " + secRes);
				// USER TOKEN
				if ((action & WSConstants.UT) > 0) {
					WSUsernameTokenPrincipal
principal = (WSUsernameTokenPrincipal)
secRes.getPrincipal();
					logger.debug("name=" +
principal.getName());
					logger.debug("password=" +
principal.getPassword());
					logger.debug("passwordType=" +
principal.getPasswordType());
					logger.debug("createdTime=" +
principal.getCreatedTime());

					if (principal.getPassword() ==
null) {
						throw new
RuntimeException("Invalid Security Header");
					} else {
                                                // NOW COMPARE PASSWORDS
-
HOW????
						userTokenValidated =
true;
					}
				}
			}
		}
		if (!userTokenValidated) {
			throw new RuntimeException("Security processing
failed");
		}
	}

So far i was able to read information from WSSE:Security header - ie.
username and pwd supplied by the Client. But i do not know how to
address
the password value supplied by AuthenticationCallbackHandler inside this
interceptor??

2) Second question: how to properly configure interceptors on client
using
spring?

To test the service i wrote simple HelloClient:

public static void main(String[] args) {

		ApplicationContext context = new
ClassPathXmlApplicationContext("/clientAppContext.xml");
		HelloWorld client = (HelloWorld)
context.getBean("client");
		System.out.println("Invoking service...");
		String text = client.sayHi("Domagoj");
		System.out.println("Response=: " + text);
	}

This is my clientAppContext.xml:

<bean id="client" class="demo.spring.HelloWorld" 
factory-bean="clientFactory" factory-method="create"/>

	<bean id="clientFactory"
class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
	  <property name="serviceClass" value="demo.spring.HelloWorld"/>
	  <property name="address"
value="http://localhost:8080/SoaLab/HelloWorld"/>
	  <property name="outInterceptors">
			<list>
				<bean
class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
				<bean
class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
					<property name="properties">
						<map>
							<entry
key="action" value="UsernameToken"/>
							<entry
key="user" value="joe"/>
							<entry
key="passwordType" value="PasswordText"/>
							<entry
key="passwordCallbackClass"
value="demo.interceptors.ClientPasswordCallback"/>
						</map>
					</property>
				</bean>
			</list>
		</property>
	</bean>

The problem i have is that Response i receive from HelloWorld service is
null??
If i comment interceptors on both client and server side it all works
fine.

Any suggestions?

Thx in advance....


-- 
View this message in context:
http://www.nabble.com/WS-Security-and-CXF-tf4340880.html#a12365374
Sent from the cxf-user mailing list archive at Nabble.com.

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland