cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrei Shakirin <ashaki...@talend.com>
Subject RE: Dispatching WS with WSS4J through STS
Date Mon, 22 Oct 2012 10:31:53 GMT
Hi,

OK, MEX call seems to be successful now.
The problem occurs on the next step by building service model from the WSDL.

Could you intercept wire message (request and response) for MEX communication and put it here?

Regards,
Andrei.

-----Original Message-----
From: Mitrik Dieter, A15 Entwicklung Qualit├Ątsmanagement und technisches Marketing [mailto:Mitrik.Dieter@akdb.de]

Sent: Montag, 22. Oktober 2012 11:42
To: users@cxf.apache.org
Subject: AW: Dispatching WS with WSS4J through STS

Hello Andrei,

I have tried the suggestions from here and your other message. I got a little further, but
there is still problems.

Here is the current exception, after working in the MEX changes:
"""
2012-10-22 11:16:26,913 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain  - Invoking
handleMessage on interceptor org.apache.cxf.interceptor.StaxInEndingInterceptor@1e75e89
org.apache.cxf.wsdl11.WSDLRuntimeException: Part rstMessage defined as element {http://schemas.message.com/Message}MessageBody
which is not in the schema.
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildMessage(WSDLServiceBuilder.java:865)
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildInterfaceOperation(WSDLServiceBuilder.java:593)
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildInterface(WSDLServiceBuilder.java:571)
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildServices(WSDLServiceBuilder.java:347)
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildServices(WSDLServiceBuilder.java:196)
	at org.apache.cxf.wsdl11.WSDLServiceBuilder.buildServices(WSDLServiceBuilder.java:172)
	at org.apache.cxf.wsdl11.WSDLServiceFactory.create(WSDLServiceFactory.java:119)
	at *.Osci2ClientTest$MySTSClient.configureViaEPR(Osci2ClientTest.java:269)
	at *.Osci2ClientTest$SetSTSClientOutInterceptor.handleMessage(Osci2ClientTest.java:223)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
"""

The service that I want to consume is: http://gov-test.osci2.bos-asp.de/OSCI2Endpoint/user/Alice
, MEX=http://gov-test.osci2.bos-asp.de/governikus-sts/IdProviderUsernamePassword/mex


Here are the relevant code snippets:
"""
		((DispatchImpl<?>)dispatch).getClient().getOutInterceptors().add(new SetSTSClientOutInterceptor());
	...

	public static class SetSTSClientOutInterceptor extends AbstractPhaseInterceptor<Message>
{
		public SetSTSClientOutInterceptor() {
			super(Phase.PREPARE_SEND);
			getBefore().add("IssuedTokenOutInterceptor");
		}

		@Override
		public void handleMessage(Message message) throws Fault {
			STSClient stsClient = new MySTSClient(message.getExchange().get(Bus.class));
			stsClient.setSoap12();
			stsClient.setEndpointName(message.getExchange().getEndpoint().getEndpointInfo().getName().toString());
			stsClient.setServiceName("{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService");
			message.setContextualProperty(SecurityConstants.STS_CLIENT, stsClient);

			AssertionInfoMap aim = message.get(AssertionInfoMap.class);
			// extract Assertion information
			if (aim != null) {
				Collection<AssertionInfo> ais = aim.get(SP12Constants.ISSUED_TOKEN);
				if (ais == null || ais.isEmpty()) {
					return;
				}
				if (isRequestor(message)) {
					IssuedToken itok = (IssuedToken) ais.iterator().next().getAssertion();
					if (itok.getIssuerEpr() != null) {
						// configure via mex
						boolean useEPRWSAAddrAsMEXLocation = !Boolean
								.valueOf((String) message
										.getContextualProperty(SecurityConstants.DISABLE_STS_CLIENT_WSMEX_CALL_USING_EPR_ADDRESS));
						stsClient.configureViaEPR(itok.getIssuerEpr(), useEPRWSAAddrAsMEXLocation);
					}
				}
			}
		}
	}

	public static class MySTSClient extends STSClient {
	...
		@Override
		public void configureViaEPR(EndpointReferenceType ref, boolean useEPRWSAAddrAsMEXLocation)
{
	...
						proxyFac.setBindingId(SoapBindingConstants.SOAP12_BINDING_ID);
	...
"""


Thank you in advance,
  Dieter

----------------

See answers bellow

>[dam] I tried creating a STSClient inside an interceptor 
>(list=dispatch.client.out, phase=PREPARE_SEND,
>before=IssuedTokenOutInterceptor) and assign it to the context. I 
>created the client following STSUtils#getClient(); unfortunately, it 
>NPEed at org.apache.cxf.transport.TransportFinder.findTransportForURI
>because URI|location was null. In the default case, STSUtils would set 
>the location from IssuedToken.EPR. What is the equivalent for my interceptor#handleMessage()?
Is there a less clunky way to achieve this?

a) By default IssuedTokenOutInterceptor uses address from IssuedToken/Issuer WS-Policy element.
You can do it exactly the same way:
                Collection<AssertionInfo> ais = aim.get(SP12Constants.ISSUED_TOKEN);
	...
                IssuedToken itok = (IssuedToken)ais.iterator().next().getAssertion();
                ...
                STSClient client = STSUtils.getClient(message, "sts", itok);

b) Other option is just create STSClient manually and set necessary properties:
            STSClient stsClient = (STSClient) message.getExchange().get(SecurityConstants.STS_CLIENT);
            if (stsClient == null) {
                stsClient = new STSClient(message.getExchange().getBus());
            }
            stsClient.setWsdlLocation(stsEndpoint + "?wsdl");
            stsClient.setServiceName(AuthenticationConstants.STS_SERVICE_NAME);
            stsClient.setEndpointName(AuthenticationConstants.STS_ENDPOINT_NAME);

            Map<String, Object> props = new HashMap<String, Object>();
            props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");
            props.put(SecurityConstants.STS_TOKEN_USERNAME, AuthenticationConstants.CONSUMER_ALIAS);
            props.put(SecurityConstants.IS_BSP_COMPLIANT, "false");
            stsClient.setProperties(props);

            message.getExchange().put(SecurityConstants.STS_CLIENT, stsClient);

stsEndpoint is endpoint of your STS service; AuthenticationConstants.STS_SERVICE_NAME is {http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService";
AuthenticationConstants.STS_ENDPOINT_NAME is "{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}X509_Port".

Here you can also set Soap 1.2 binding using stsClient.setSoap12();

>[dam] Adding the suggested properties to dispatch.requestContext did 
>not add any interceptors to the STS Endpoint chain which in turn did not add the necessary
elements into the outgoing message. Is this a consequence of the failing MEX above? Where
would the interceptors have been injected?

Interceptors are controlled by WS-Policy and will be added automatically via InterceptorProviders.
InterceptorProviders specify relationships between WS-Policy assertions and interceptors.


>[dam] Thanks, this is more to my liking. Wouldn't it be even nicer to 
>make a WebServiceFeature out of this, so that service.createDispatch(..,..,.., new SecurityFeature(mysignprops,
myencprops)?

Not sure does it make sense. Setting properties in request context works for all types of
clients (generated, configured via Spring/Blueprint), not only for Dispatch. But you welcome
to create improvement request in CXF Jira and submit a patch.

Regards,
Andrei.



Hello,

thank you for your suggestions.
See comments below [dam].

Thank you in advance.
-------------------------


I would recommend do not configure WSS4JOutterceptor directly in code, but do it using WS-Policy.
As sample you can take http://svn.apache.org/repos/asf/cxf/branches/2.3.x-fixes/systests/ws-specs/src/test/java/org/apache/cxf/systest/ws/security/SecurityPolicyTest.java

Code looks like:
       // DoubleIt.wsdl specifies WS-policy
        URL wsdl = SecurityPolicyTest.class.getResource("DoubleIt.wsdl");
        Service service = Service.create(wsdl, SERVICE_QNAME);
        
        QName portQName = new QName(NAMESPACE, "DoubleItPortEncryptThenSign");
        Dispatch<Source> disp = service.createDispatch(portQName, Source.class, Mode.PAYLOAD);
        
        disp.getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, 
                                     new KeystorePasswordCallback());
        disp.getRequestContext().put(SecurityConstants.SIGNATURE_PROPERTIES,
                                     getClass().getResource("alice.properties"));
        disp.getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES, 
                                     getClass().getResource("bob.properties"));

[dam] This approach does feel more comfortable. I had been following the WS-Security user's
guide where the instructions were to use the wss4j interceptors directly.


Regarding your questions:

>2) The created service itself is a SOAP12 endpoint; however, the MEX endpoint instantiated
through STSClient uses SOAP11. The server expects SOAP12 and >fails if requested by SOAP11.
How do I force the MEX call to use SOAP12 instead of SOAP11?

STSClient has setters for both SOAP versions. Default is SOAP11. Actually I do not see configuration
property in code to change it. Seems only possible to create and configure own STSClient instance
in your Interceptor and set it into SecurityConstants.STS_CLIENT message property to be used
in IssuedTokenOutInterceptor. Will be nice to configure it via property.

[dam] I tried creating a STSClient inside an interceptor (list=dispatch.client.out, phase=PREPARE_SEND,
before=IssuedTokenOutInterceptor) and assign it to the context. I created the client following
STSUtils#getClient(); unfortunately, it NPEed at org.apache.cxf.transport.TransportFinder.findTransportForURI
because URI|location was null. In the default case, STSUtils would set the location from IssuedToken.EPR.
What is the equivalent for my interceptor#handleMessage()? Is there a less clunky way to achieve
this?


>3) Although the MEX request fails, the invocation continues to call the 
>STS. Since STSClient creates a new Endpoint, my wss4j settings on the 
>Dispatch have no effect. How can I make the STSClient Endpoint inherit its Dispatch's
wss4j settings? Or how can I identify the created Endpoint in a ClientLifecycleListener to
repeat the wss4j settings?

I think it should work out of the box with recommended way.
	
[dam] Adding the suggested properties to dispatch.requestContext did not add any interceptors
to the STS Endpoint chain which in turn did not add the necessary elements into the outgoing
message. Is this a consequence of the failing MEX above? Where would the interceptors have
been injected?


>4) Within the wss4j settings I also include Keystore information. 
>Because most of the information comes from the application, I am going 
>to preconfigure a Crypto object by SIG_PROP_REF_ID, which contains the name of a context
property. Which one is the effective context to add the Crypto object to for the implicit
STSClient Endpoint request?

Typically you just configure SecurityConstants.SIGNATURE_PROPERTIES and SecurityConstants.ENCRYPT_PROPERTIES
with properties files pointing on your keystore (like in SecurityPolicyTest.java). If it is
not appropriate for your use case (for example if keys are obtained dynamically), you can
prepare and set your own Crypto object into message using SecurityConstants.SIGNATURE_CRYPTO,
SecurityConstants.ENCRYPT_CRYPTO properties.
CXF checks these properties and will use prepared objects.

[dam] Thanks, this is more to my liking. Wouldn't it be even nicer to make a WebServiceFeature
out of this, so that service.createDispatch(..,..,.., new SecurityFeature(mysignprops, myencprops)?


Regards,
Andrei.



Hello,

I am trying to consume a webservice; since in the end many webservices will be consumed, I
am using the Dispatch interface. Since I will not know the effective webservices that are
going to be consumed I cannot declare the spring beans beforehand.
The webservice declares policies that require STS tokens. The STS defines a MEX (MetaDataExchange).

The basic consumer:
Service s = Service.create($WSDL-URL, $QName); Dispatch<> d = s.createDispatch($service-name,
$jaxb-context, PAYLOAD); Map<> wss4jProps = createWSS4JProps(); // with username, pwd,
certificates, encrypt, sign config ((DispatchImpl<>)d).getClient().getEndpoint().getOutInterceptors().add(new
WSS4JOutInterceptor(wss4jProps); d.invoke($request-message);


My questions:
1) when creating the service and dispatch objects, all referenced xsd schemas are resolved
and loaded. However, by logging the made requests (in ProxySelector), I see that the same
xsd get loaded repeatedly. Should they not be cached?
2) The created service itself is a SOAP12 endpoint; however, the MEX endpoint instantiated
through STSClient uses SOAP11. The server expects SOAP12 and fails if requested by SOAP11.
How do I force the MEX call to use SOAP12 instead of SOAP11?
3) Although the MEX request fails, the invocation continues to call the STS. Since STSClient
creates a new Endpoint, my wss4j settings on the Dispatch have no effect. How can I make the
STSClient Endpoint inherit its Dispatch's wss4j settings? Or how can I identify the created
Endpoint in a ClientLifecycleListener to repeat the wss4j settings?
4) Within the wss4j settings I also include Keystore information. Because most of the information
comes from the application, I am going to preconfigure a Crypto object by SIG_PROP_REF_ID,
which contains the name of a context property. Which one is the effective context to add the
Crypto object to for the implicit STSClient Endpoint request?


Thanks in advance,
  Dieter


Mime
View raw message