Java tutorial
/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.service.soap.client; import static java.util.Collections.emptyMap; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.cxf.message.Message.MTOM_ENABLED; import static org.apache.wss4j.common.ConfigurationConstants.ACTION; import static org.apache.wss4j.common.ConfigurationConstants.PW_CALLBACK_REF; import org.mule.runtime.extension.api.soap.security.DecryptSecurityStrategy; import org.mule.runtime.extension.api.soap.security.EncryptSecurityStrategy; import org.mule.runtime.extension.api.soap.security.SecurityStrategy; import org.mule.runtime.extension.api.soap.security.SecurityStrategyVisitor; import org.mule.runtime.extension.api.soap.security.SignSecurityStrategy; import org.mule.runtime.extension.api.soap.security.TimestampSecurityStrategy; import org.mule.runtime.extension.api.soap.security.UsernameTokenSecurityStrategy; import org.mule.runtime.extension.api.soap.security.VerifySignatureSecurityStrategy; import org.mule.runtime.soap.api.SoapVersion; import org.mule.runtime.soap.api.client.SoapClientConfiguration; import org.mule.service.soap.interceptor.NamespaceRestorerStaxInterceptor; import org.mule.service.soap.interceptor.NamespaceSaverStaxInterceptor; import org.mule.service.soap.interceptor.OutputMtomSoapAttachmentsInterceptor; import org.mule.service.soap.interceptor.OutputSoapHeadersInterceptor; import org.mule.service.soap.interceptor.SoapActionInterceptor; import org.mule.service.soap.interceptor.StreamClosingInterceptor; import org.mule.service.soap.security.SecurityStrategyCxfAdapter; import org.mule.service.soap.security.SecurityStrategyType; import org.mule.service.soap.security.WssDecryptSecurityStrategyCxfAdapter; import org.mule.service.soap.security.WssEncryptSecurityStrategyCxfAdapter; import org.mule.service.soap.security.WssSignSecurityStrategyCxfAdapter; import org.mule.service.soap.security.WssTimestampSecurityStrategyCxfAdapter; import org.mule.service.soap.security.WssUsernameTokenSecurityStrategyCxfAdapter; import org.mule.service.soap.security.WssVerifySignatureSecurityStrategyCxfAdapter; import org.mule.service.soap.security.callback.CompositeCallbackHandler; import com.google.common.collect.ImmutableList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringJoiner; import javax.security.auth.callback.CallbackHandler; import org.apache.cxf.binding.Binding; import org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor; import org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor; import org.apache.cxf.binding.soap.interceptor.Soap12FaultInInterceptor; import org.apache.cxf.endpoint.Client; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.message.Message; import org.apache.cxf.phase.PhaseInterceptor; import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.apache.cxf.wsdl.interceptors.WrappedOutInterceptor; /** * Object that creates CXF specific clients based on a {@link SoapClientConfiguration} setting all the required CXF properties. * <p> * the created client aims to be the CXF client used in the {@link SoapCxfClient}. * * @since 1.0 */ class CxfClientProvider { private final CxfClientFactory factory = new CxfClientFactory(); Client getClient(SoapClientConfiguration configuration) { boolean isMtom = configuration.isMtomEnabled(); String address = configuration.getAddress(); SoapVersion version = configuration.getVersion(); Client client = factory.createClient(address, version.getVersion()); addSecurityInterceptors(client, getAdaptedSecurities(configuration.getSecurities())); addRequestInterceptors(client); addResponseInterceptors(client, isMtom); client.getEndpoint().put(MTOM_ENABLED, isMtom); removeUnnecessaryCxfInterceptors(client); return client; } private List<SecurityStrategyCxfAdapter> getAdaptedSecurities(List<SecurityStrategy> securities) { ImmutableList.Builder<SecurityStrategyCxfAdapter> builder = ImmutableList.builder(); securities.forEach(s -> s.accept(new SecurityStrategyVisitor() { @Override public void visitEncrypt(EncryptSecurityStrategy encrypt) { builder.add(new WssEncryptSecurityStrategyCxfAdapter(encrypt.getKeyStoreConfiguration())); } @Override public void visitDecrypt(DecryptSecurityStrategy decrypt) { builder.add(new WssDecryptSecurityStrategyCxfAdapter(decrypt.getKeyStoreConfiguration())); } @Override public void visitUsernameToken(UsernameTokenSecurityStrategy usernameToken) { builder.add(new WssUsernameTokenSecurityStrategyCxfAdapter(usernameToken)); } @Override public void visitSign(SignSecurityStrategy sign) { builder.add(new WssSignSecurityStrategyCxfAdapter(sign.getKeyStoreConfiguration())); } @Override public void visitVerify(VerifySignatureSecurityStrategy verify) { WssVerifySignatureSecurityStrategyCxfAdapter adapter = verify.getTrustStoreConfiguration() .map(WssVerifySignatureSecurityStrategyCxfAdapter::new) .orElse(new WssVerifySignatureSecurityStrategyCxfAdapter()); builder.add(adapter); } @Override public void visitTimestamp(TimestampSecurityStrategy timestamp) { builder.add(new WssTimestampSecurityStrategyCxfAdapter(timestamp.getTimeToLeaveInSeconds())); } })); return builder.build(); } private void addSecurityInterceptors(Client client, List<SecurityStrategyCxfAdapter> securityStrategies) { Map<String, Object> requestProps = buildSecurityProperties(securityStrategies, SecurityStrategyType.OUTGOING); if (!requestProps.isEmpty()) { client.getOutInterceptors().add(new WSS4JOutInterceptor(requestProps)); } Map<String, Object> responseProps = buildSecurityProperties(securityStrategies, SecurityStrategyType.INCOMING); if (!responseProps.isEmpty()) { client.getInInterceptors().add(new WSS4JInInterceptor(responseProps)); } } private Map<String, Object> buildSecurityProperties(List<SecurityStrategyCxfAdapter> strategies, SecurityStrategyType type) { if (strategies.isEmpty()) { return emptyMap(); } Map<String, Object> props = new HashMap<>(); StringJoiner actionsJoiner = new StringJoiner(" "); ImmutableList.Builder<CallbackHandler> callbackHandlersBuilder = ImmutableList.builder(); strategies.stream().filter(securityStrategy -> securityStrategy.securityType().equals(type)) .forEach(securityStrategy -> { props.putAll(securityStrategy.buildSecurityProperties()); actionsJoiner.add(securityStrategy.securityAction()); securityStrategy.buildPasswordCallbackHandler().ifPresent(callbackHandlersBuilder::add); }); List<CallbackHandler> handlers = callbackHandlersBuilder.build(); if (!handlers.isEmpty()) { props.put(PW_CALLBACK_REF, new CompositeCallbackHandler(handlers)); } String actions = actionsJoiner.toString(); if (isNotBlank(actions)) { // the list of actions is passed as a String with the action names separated by a black space. props.put(ACTION, actions); } // This Map needs to be mutable, cxf will add properties if needed. return props; } private void addRequestInterceptors(Client client) { List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors(); outInterceptors.add(new SoapActionInterceptor()); } private void addResponseInterceptors(Client client, boolean mtomEnabled) { List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors(); inInterceptors.add(new NamespaceRestorerStaxInterceptor()); inInterceptors.add(new NamespaceSaverStaxInterceptor()); inInterceptors.add(new StreamClosingInterceptor()); inInterceptors.add(new CheckFaultInterceptor()); inInterceptors.add(new OutputSoapHeadersInterceptor()); inInterceptors.add(new SoapActionInterceptor()); if (mtomEnabled) { inInterceptors.add(new OutputMtomSoapAttachmentsInterceptor()); } } private void removeUnnecessaryCxfInterceptors(Client client) { Binding binding = client.getEndpoint().getBinding(); removeInterceptor(binding.getOutInterceptors(), WrappedOutInterceptor.class.getName()); removeInterceptor(binding.getInInterceptors(), Soap11FaultInInterceptor.class.getName()); removeInterceptor(binding.getInInterceptors(), Soap12FaultInInterceptor.class.getName()); removeInterceptor(binding.getInInterceptors(), CheckFaultInterceptor.class.getName()); } private void removeInterceptor(List<Interceptor<? extends Message>> inInterceptors, String name) { inInterceptors.removeIf(i -> i instanceof PhaseInterceptor && ((PhaseInterceptor) i).getId().equals(name)); } }