1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package org.ogf.graap.wsag.client.remote;
36
37 import java.io.ByteArrayInputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.math.BigInteger;
42 import java.net.URL;
43 import java.security.cert.X509Certificate;
44 import java.text.MessageFormat;
45 import java.util.Properties;
46 import java.util.Set;
47 import java.util.Vector;
48
49 import javax.security.auth.login.LoginContext;
50 import javax.xml.namespace.QName;
51 import javax.xml.stream.XMLStreamException;
52 import javax.xml.stream.XMLStreamReader;
53
54 import org.apache.axiom.om.OMElement;
55 import org.apache.axiom.om.util.StAXUtils;
56 import org.apache.axiom.soap.SOAPEnvelope;
57 import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
58 import org.apache.axis2.AxisFault;
59 import org.apache.axis2.client.OperationClient;
60 import org.apache.axis2.client.ServiceClient;
61 import org.apache.axis2.context.ConfigurationContext;
62 import org.apache.axis2.context.ConfigurationContextFactory;
63 import org.apache.axis2.context.MessageContext;
64 import org.apache.axis2.transport.http.HTTPConstants;
65 import org.apache.log4j.Logger;
66 import org.apache.muse.util.messages.Messages;
67 import org.apache.muse.util.messages.MessagesFactory;
68 import org.apache.muse.util.xml.XmlUtils;
69 import org.apache.muse.ws.addressing.EndpointReference;
70 import org.apache.muse.ws.addressing.soap.SimpleSoapClient;
71 import org.apache.muse.ws.addressing.soap.SoapConstants;
72 import org.apache.muse.ws.addressing.soap.SoapFault;
73 import org.apache.ws.security.WSConstants;
74 import org.apache.ws.security.WSSecurityEngineResult;
75 import org.apache.ws.security.WSSecurityException;
76 import org.apache.ws.security.components.crypto.Crypto;
77 import org.apache.ws.security.handler.WSHandlerConstants;
78 import org.apache.ws.security.handler.WSHandlerResult;
79 import org.apache.xmlbeans.XmlObject;
80 import org.ogf.graap.wsag.api.WsagConstants;
81 import org.ogf.graap.wsag.api.configuration.WSAG4JConfiguration;
82 import org.ogf.graap.wsag.api.security.ISecurityProperties;
83 import org.ogf.graap.wsag.security.core.SecurityConstants;
84 import org.ogf.graap.wsag.security.core.client.ClientSecurityHandler;
85 import org.ogf.graap.wsag4j.types.configuration.ConfigurationType;
86 import org.ogf.graap.wsag4j.types.configuration.HandlerType;
87 import org.ogf.graap.wsag4j.types.configuration.WSRFClientConfigurationType;
88 import org.w3c.dom.Document;
89 import org.w3c.dom.Element;
90
91
92
93
94
95
96
97 public class Axis2SoapClient extends SimpleSoapClient
98 {
99
100
101
102
103
104 public static int DEFAULT_TIME_OUT_IN_MILLI_SECONDS = 2 * 60 * 1000;
105
106
107
108 private static final Logger LOG = Logger.getLogger( Axis2SoapClient.class );
109
110
111
112
113 private static ConfigurationType config = null;
114
115
116
117
118 private static ConfigurationContext configurationContext = null;
119
120
121
122
123 private static final Element[] EMPTY_ARRAY = new Element[0];
124
125
126
127
128 private static final Messages MESSAGES = MessagesFactory.get( SimpleSoapClient.class );
129
130
131
132
133 private Properties properties = new Properties();
134
135
136
137
138 private final ISecurityProperties securityProperties;
139
140 private Crypto crypto;
141
142
143
144
145
146
147
148 public Axis2SoapClient( ISecurityProperties securityProperties )
149 {
150 super();
151 this.securityProperties = securityProperties;
152 initialize();
153 }
154
155
156
157
158 protected void initialize()
159 {
160
161
162
163 LoginContext context = securityProperties.getLoginContext();
164
165 if ( context != null )
166 {
167 Set<Crypto> userCrypto = context.getSubject().getPrivateCredentials( Crypto.class );
168 if ( !userCrypto.isEmpty() )
169 {
170 crypto = userCrypto.iterator().next();
171 }
172 }
173
174
175
176
177 synchronized ( Axis2SoapClient.class )
178 {
179
180 try
181 {
182 if ( config == null )
183 {
184 config =
185 WSAG4JConfiguration.findWSAG4JConfiguration( WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE );
186 }
187 }
188 catch ( IOException e )
189 {
190 Object[] filler = new Object[] { WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE };
191 String message =
192 MessageFormat.format( "Failed to read wsag4j client configuration file {0}.", filler );
193 throw new RuntimeException( message );
194 }
195
196 try
197 {
198
199
200
201
202
203 if ( configurationContext == null )
204 {
205 URL repoURL = Axis2SoapClient.class.getResource( "/axis2-client/" );
206 URL fileURL = Axis2SoapClient.class.getResource( "/axis2-client/client.axis2.xml" );
207 configurationContext =
208 ConfigurationContextFactory.createConfigurationContextFromURIs( fileURL, repoURL );
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 }
231 }
232 catch ( Exception e )
233 {
234 Object[] filler = new Object[] { e.getMessage() };
235 String message =
236 MessageFormat.format( "Failed to read axis2 client configuration. Error: {0}.", filler );
237 throw new RuntimeException( message, e );
238 }
239 }
240 }
241
242
243
244
245 @Override
246 protected Element createMessage( EndpointReference source, EndpointReference destination, String action,
247 Element[] bodyElements, Element[] extraHeaders )
248 {
249 Element[] additionalHeaders = generateExtraHeaders();
250 if ( additionalHeaders == null )
251 {
252 additionalHeaders = EMPTY_ARRAY;
253 }
254
255 Element[] headers;
256
257 if ( extraHeaders.length == 0 )
258 {
259
260 headers = additionalHeaders;
261 }
262 else
263 {
264
265 Vector<Element> tmpHeaders = new Vector<Element>();
266 for ( int i = 0; i < extraHeaders.length; i++ )
267 {
268 tmpHeaders.add( extraHeaders[i] );
269 }
270
271 for ( int i = 0; i < additionalHeaders.length; i++ )
272 {
273 tmpHeaders.add( additionalHeaders[i] );
274 }
275
276 headers = tmpHeaders.toArray( new Element[tmpHeaders.size()] );
277 }
278
279
280 return super.createMessage( source, destination, action, bodyElements, headers );
281 }
282
283
284
285
286 @Override
287 public Element[] send( EndpointReference src, EndpointReference dest, String wsaAction, Element[] body,
288 Element[] extraHeaders )
289 {
290 if ( dest == null )
291 {
292 throw new NullPointerException( MESSAGES.get( "NullDestinationEPR" ) );
293 }
294
295 if ( wsaAction == null )
296 {
297 throw new NullPointerException( MESSAGES.get( "NullActionURI" ) );
298 }
299
300 if ( body == null )
301 {
302 body = EMPTY_ARRAY;
303 }
304
305 if ( extraHeaders == null )
306 {
307 extraHeaders = EMPTY_ARRAY;
308 }
309
310
311
312
313 Element soapRequest = createMessage( src, dest, wsaAction, body, extraHeaders );
314
315 if ( isUsingTrace() )
316 {
317 trace( soapRequest, false );
318 }
319
320 Element soapResponse = null;
321
322 try
323 {
324
325
326
327
328 soapResponse = doAxisCall( soapRequest, dest, wsaAction );
329 }
330
331
332
333
334
335 catch ( AxisFault error )
336 {
337 SoapFault soapFault = new SoapFault( error.getMessage(), error );
338 if ( error.getFaultCode() != null )
339 {
340 soapFault.setCode( error.getFaultCode() );
341 }
342
343 if ( ( error.getFaultSubCodes() != null ) && ( error.getFaultSubCodes().size() > 0 ) )
344 {
345 soapFault.setSubCode( (QName) error.getFaultSubCodes().get( 0 ) );
346 }
347
348 try
349 {
350 OMElement detail = error.getDetail();
351
352 ByteArrayOutputStream detailOut = new ByteArrayOutputStream();
353 detail.serialize( detailOut );
354
355 ByteArrayInputStream detailIn = new ByteArrayInputStream( detailOut.toByteArray() );
356 soapFault.setDetail( XmlUtils.createDocument( detailIn ).getDocumentElement() );
357 }
358 catch ( Exception e )
359 {
360 return new Element[] { soapFault.toXML() };
361 }
362 return new Element[] { soapFault.toXML() };
363 }
364
365
366 catch ( Throwable error )
367 {
368 SoapFault soapFault = new SoapFault( error.getMessage(), error );
369 return new Element[] { soapFault.toXML() };
370 }
371
372 if ( isUsingTrace() )
373 {
374 trace( soapResponse, true );
375 }
376
377
378
379
380 Element responseBody = XmlUtils.getElement( soapResponse, SoapConstants.BODY_QNAME );
381 return XmlUtils.getAllElements( responseBody );
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 protected Element doAxisCall( Element soapRequest, EndpointReference dest, String wsaAction )
399 throws AxisFault
400 {
401
402
403
404
405
406
407
408 MessageContext currentContext = new MessageContext();
409 MessageContext oldContext = MessageContext.getCurrentMessageContext();
410 MessageContext.setCurrentMessageContext( currentContext );
411
412 ServiceClient client = new org.apache.axis2.client.ServiceClient( configurationContext, null );
413
414 org.apache.axis2.addressing.EndpointReference to =
415 new org.apache.axis2.addressing.EndpointReference( dest.getAddress().toString() );
416 client.getOptions().setTo( to );
417
418
419
420
421 OperationClient oc = client.createClient( ServiceClient.ANON_OUT_IN_OP );
422
423 try
424 {
425
426
427 String serializedMessage = XmlUtils.toString( soapRequest, false, false );
428 InputStream in = new ByteArrayInputStream( serializedMessage.getBytes() );
429
430 XMLStreamReader reader;
431
432 try
433 {
434 reader = StAXUtils.createXMLStreamReader( in );
435 }
436 catch ( XMLStreamException e )
437 {
438 String message = "Error creating axis call from SOAP request";
439 throw new AxisFault( message, e );
440 }
441 StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder( reader );
442
443
444
445 SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement();
446
447
448 currentContext.setProperty( SecurityConstants.CRYPTO_SIGN, getCrypto() );
449 currentContext.setProperty( HTTPConstants.AUTO_RELEASE_CONNECTION, new Boolean( true ) );
450
451
452 currentContext.getOptions().setTimeOutInMilliSeconds( DEFAULT_TIME_OUT_IN_MILLI_SECONDS );
453
454 currentContext.setEnvelope( envelope );
455
456 oc.addMessageContext( currentContext );
457 oc.getOptions().setAction( wsaAction );
458
459
460
461
462
463
464
465
466 if ( LOG.isTraceEnabled() )
467 {
468 LOG.trace( MessageFormat.format( "starting call to ", new Object[] { dest.getAddress() } ) );
469 }
470
471 oc.execute( true );
472
473 if ( LOG.isTraceEnabled() )
474 {
475 LOG.trace( MessageFormat.format( "received response from ",
476 new Object[] { dest.getAddress() } ) );
477 }
478
479
480
481
482
483 MessageContext returnMessageContext =
484 oc.getMessageContext( org.apache.axis2.wsdl.WSDLConstants.MESSAGE_LABEL_IN_VALUE );
485
486 SOAPEnvelope returnEnv = returnMessageContext.getEnvelope();
487
488 XMLStreamReader resultReader = returnEnv.getXMLStreamReaderWithoutCaching();
489
490
491
492
493
494 processSecurityResults( returnMessageContext );
495
496 return parseResponse( resultReader );
497
498 }
499 finally
500 {
501 oc.complete( currentContext );
502 MessageContext.setCurrentMessageContext( oldContext );
503 }
504 }
505
506 @SuppressWarnings( "unchecked" )
507 private void processSecurityResults( MessageContext context ) throws AxisFault
508 {
509 try
510 {
511 Vector<WSHandlerResult> handlerResults =
512 (Vector<WSHandlerResult>) context.getProperty( WSHandlerConstants.RECV_RESULTS );
513
514
515
516
517 if ( handlerResults != null )
518 {
519
520 for ( int i = 0; i < handlerResults.size(); i++ )
521 {
522 WSHandlerResult currentResult = handlerResults.get( i );
523
524 Vector<WSSecurityEngineResult> wsSecEngineResults = currentResult.getResults();
525
526 for ( int j = 0; j < wsSecEngineResults.size(); j++ )
527 {
528 WSSecurityEngineResult wser = wsSecEngineResults.get( j );
529 if ( ( (Integer) wser.get( WSSecurityEngineResult.TAG_ACTION ) ).intValue() == WSConstants.SIGN
530 && wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATE ) != null )
531 {
532
533
534 X509Certificate certificate =
535 (X509Certificate) wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATE );
536 properties.put( SecurityConstants.X509_SERVER_CERTIFICATE, certificate );
537
538 String issuerString = certificate.getIssuerDN().getName();
539 BigInteger issuerSerial = certificate.getSerialNumber();
540 String alias = getCrypto().getAliasForX509Cert( issuerString, issuerSerial );
541
542 if ( alias != null )
543 {
544
545 try
546 {
547 X509Certificate[] certs = getCrypto().getCertificates( alias );
548 properties.put( SecurityConstants.X509_SERVER_CERTIFICATE_CHAIN, certs );
549 }
550 catch ( WSSecurityException ex )
551 {
552 String msgError =
553 "Axis2SoapClient: Could not get certificates for alias " + alias;
554 throw new WSSecurityException( msgError, ex );
555 }
556 }
557 }
558
559 if ( ( (Integer) wser.get( WSSecurityEngineResult.TAG_ACTION ) ).intValue() == WSConstants.BST
560 && wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATES ) != null )
561 {
562
563
564 X509Certificate[] certificates =
565 (X509Certificate[]) wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATES );
566 properties.put( SecurityConstants.X509_SERVER_CERTIFICATE_CHAIN, certificates );
567 }
568 }
569
570 }
571 }
572 }
573 catch ( Exception e )
574 {
575 throw new AxisFault( "Axis2SoapClient: Error while processing security handler results.", e );
576 }
577 }
578
579 private Element parseResponse( XMLStreamReader reader ) throws AxisFault
580 {
581 try
582 {
583 XmlObject parsedResult = XmlObject.Factory.parse( reader );
584
585 if ( parsedResult.getDomNode() instanceof Document )
586 {
587 return XmlUtils.getFirstElement( parsedResult.getDomNode() );
588 }
589 if ( parsedResult.getDomNode() instanceof Element )
590 {
591 return (Element) parsedResult.getDomNode();
592 }
593
594 String message = "Response document is not of type document or element or null.";
595 throw new AxisFault( message );
596 }
597 catch ( Exception e )
598 {
599 String message = "Error in deserializing the Axis response.";
600 throw new AxisFault( message, e );
601 }
602 }
603
604
605
606
607
608
609 protected Element[] generateExtraHeaders()
610 {
611
612 Vector<Element> extraHeaders = new Vector<Element>();
613 ClientSecurityHandler[] handler = getSecurityHandler();
614 for ( int i = 0; i < handler.length; i++ )
615 {
616 Element[] tmpHeaders = handler[i].createHeader( securityProperties );
617 for ( int j = 0; j < tmpHeaders.length; j++ )
618 {
619 extraHeaders.add( tmpHeaders[j] );
620 }
621 }
622
623 return extraHeaders.toArray( new Element[extraHeaders.size()] );
624 }
625
626
627
628
629 protected ClientSecurityHandler[] getSecurityHandler()
630 {
631
632 if ( config == null )
633 {
634 Object[] filler = new Object[] { WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE };
635 String message =
636 MessageFormat.format( "The client configuration file {0} was not found.", filler );
637 LOG.warn( message );
638
639 return new ClientSecurityHandler[0];
640 }
641
642 WSRFClientConfigurationType wsrfConfig = config.getWSRFClientConfiguration();
643
644 if ( wsrfConfig.isSetSecurityHandlerChain() )
645 {
646 HandlerType[] handler = wsrfConfig.getSecurityHandlerChain().getHandlerArray();
647 ClientSecurityHandler[] result = new ClientSecurityHandler[handler.length];
648
649 for ( int i = 0; i < handler.length; i++ )
650 {
651 String implementationClass = handler[i].getImplementationClass();
652 String handlerName = handler[i].getHandlerName();
653
654 try
655 {
656 @SuppressWarnings( "unchecked" )
657 Class<ClientSecurityHandler> implementation =
658 (Class<ClientSecurityHandler>) Class.forName( implementationClass );
659 result[i] = implementation.newInstance();
660 }
661 catch ( ClassNotFoundException e )
662 {
663 Object[] filler = new Object[] { implementationClass, handlerName };
664 String message =
665 MessageFormat.format(
666 "The implementation class {0} for handler {1} could not be found.", filler );
667 throw new RuntimeException( message );
668 }
669 catch ( IllegalAccessException e )
670 {
671 Object[] filler = new Object[] { implementationClass, handlerName, e.getMessage() };
672 String msgError =
673 "The implementation class {0} for handler {1} could not be accessed. [{2}]";
674 String message = MessageFormat.format( msgError, filler );
675 throw new RuntimeException( message );
676 }
677 catch ( InstantiationException e )
678 {
679 Object[] filler = new Object[] { implementationClass, handlerName, e.getMessage() };
680 String msgError =
681 "The implementation class {0} for handler {1} could not be instantiated. [{2}]";
682 String message = MessageFormat.format( msgError, filler );
683 throw new RuntimeException( message );
684 }
685 catch ( ClassCastException e )
686 {
687 Object[] filler =
688 new Object[] { implementationClass, ClientSecurityHandler.class.getName() };
689 String msgError = "The implementation class {0} does not implement the interface {1}.";
690 String message = MessageFormat.format( msgError, filler );
691 throw new RuntimeException( message );
692 }
693 }
694
695 return result;
696 }
697 else
698 {
699 return new ClientSecurityHandler[0];
700 }
701
702 }
703
704
705
706
707 public Properties getProperties()
708 {
709 return properties;
710 }
711
712
713
714
715
716 public void setProperties( Properties properties )
717 {
718 this.properties = properties;
719 }
720
721
722
723
724 public Crypto getCrypto()
725 {
726 return crypto;
727 }
728 }