/* * #%L * Talend :: ESB :: Job :: Controller * %% * Copyright (C) 2011 - 2012 Talend Inc. * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.talend.esb.job.controller.internal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import org.apache.cxf.Bus; import org.apache.cxf.bus.extension.Extension; import org.apache.cxf.bus.extension.ExtensionManager; import org.apache.cxf.bus.extension.ExtensionManagerImpl; import org.apache.cxf.bus.extension.ExtensionRegistry; import org.apache.cxf.feature.Feature; import org.apache.cxf.headers.Header; import org.apache.cxf.service.factory.FactoryBeanListenerManager; import org.apache.neethi.Policy; import org.apache.wss4j.common.crypto.Crypto; import org.talend.esb.job.controller.ESBEndpointConstants; import org.talend.esb.job.controller.ESBEndpointConstants.EsbSecurity; import org.talend.esb.policy.correlation.feature.CorrelationIDFeature; import org.talend.esb.sam.agent.feature.EventFeature; import org.talend.esb.security.policy.PolicyProvider; import org.w3c.dom.Document; import org.w3c.dom.Node; import routines.system.api.ESBConsumer; import routines.system.api.ESBEndpointInfo; import routines.system.api.ESBEndpointRegistry; public class RuntimeESBEndpointRegistry implements ESBEndpointRegistry { private static final Logger LOG = Logger.getLogger(RuntimeESBEndpointRegistry.class.getName()); private static final String WSDL_CLIENT_EXTENSION_NAME = "org.talend.esb.registry.client.wsdl.RegistryFactoryBeanListener"; private static final String POLICY_CLIENT_EXTENSION_NAME = "org.talend.esb.registry.client.policy.RegistryFactoryBeanListener"; private Bus bus; private EventFeature samFeature; private PolicyProvider policyProvider; private Map<String, String> clientProperties; private Crypto cryptoProvider; public void setBus(Bus bus) { this.bus = bus; } public void setSamFeature(EventFeature samFeature) { this.samFeature = samFeature; } public void setPolicyProvider(PolicyProvider policyProvider) { this.policyProvider = policyProvider; } public void setClientProperties(Map<String, String> clientProperties) { this.clientProperties = clientProperties; } public void setCryptoProvider(Crypto cryptoProvider) { this.cryptoProvider = cryptoProvider; } @Override public ESBConsumer createConsumer(ESBEndpointInfo endpoint) { final Map<String, Object> props = endpoint.getEndpointProperties(); boolean useServiceRegistry = getBoolean(props, ESBEndpointConstants.USE_SERVICE_REGISTRY); final String authorizationRole = (String) props.get(ESBEndpointConstants.AUTHZ_ROLE); boolean useCrypto = getBoolean(props, ESBEndpointConstants.USE_CRYPTO); final EsbSecurity esbSecurity = EsbSecurity.fromString((String) props.get(ESBEndpointConstants.ESB_SECURITY)); Policy policy = buildSecurePolicy(authorizationRole, useCrypto, esbSecurity); final SecurityArguments securityArguments = new SecurityArguments( esbSecurity, policy, (String) props.get(ESBEndpointConstants.USERNAME), (String) props.get(ESBEndpointConstants.PASSWORD), (String) props.get(ESBEndpointConstants.ALIAS), clientProperties, authorizationRole, props.get(ESBEndpointConstants.SECURITY_TOKEN), (useCrypto || useServiceRegistry) ? cryptoProvider : null); List<Header> soapHeaders = listSoapHeaders(props.get(ESBEndpointConstants.SOAP_HEADERS)); if (useServiceRegistry) { ensureServiceRegistryAvailable(bus); } final QName serviceName = QName.valueOf((String) props.get(ESBEndpointConstants.SERVICE_NAME)); String operationNamespace = (String) props.get(ESBEndpointConstants.OPERATION_NAMESPACE); final QName operationName = new QName( (null == operationNamespace) ? serviceName.getNamespaceURI() : operationNamespace, (String) props.get(ESBEndpointConstants.DEFAULT_OPERATION_NAME)); return new RuntimeESBConsumer( serviceName, QName.valueOf((String) props.get(ESBEndpointConstants.PORT_NAME)), operationName, (String) props.get(ESBEndpointConstants.PUBLISHED_ENDPOINT_URL), (String) props.get(ESBEndpointConstants.WSDL_URL), getBoolean(props, ESBEndpointConstants.USE_SERVICE_LOCATOR), (Map<String, String>) props.get(ESBEndpointConstants.REQUEST_SL_PROPS), getBoolean(props, ESBEndpointConstants.USE_SERVICE_ACTIVITY_MONITOR) ? samFeature : null, useServiceRegistry, securityArguments, bus, getBoolean(props, ESBEndpointConstants.LOG_MESSAGES), soapHeaders, (Feature)props.get("httpHeadersFeature"), getBoolean(props, ESBEndpointConstants.ENHANCED_RESPONSE), props.get(CorrelationIDFeature.CORRELATION_ID_CALLBACK_HANDLER)); } private Policy buildSecurePolicy(final String authorizationRole, boolean useCrypto, final EsbSecurity esbSecurity) { Policy policy = null; if (EsbSecurity.TOKEN == esbSecurity) { policy = policyProvider.getUsernamePolicy(bus); } else if (EsbSecurity.SAML == esbSecurity) { if (null != authorizationRole) { if (useCrypto) { policy = policyProvider.getSAMLAuthzCryptoPolicy(bus); } else { policy = policyProvider.getSAMLAuthzPolicy(bus); } } else { if (useCrypto) { policy = policyProvider.getSAMLCryptoPolicy(bus); } else { policy = policyProvider.getSAMLPolicy(bus); } } } return policy; } @SuppressWarnings("unchecked") private List<Header> listSoapHeaders(Object soapHeadersObject) throws TransformerFactoryConfigurationError { if (null != soapHeadersObject) { if (soapHeadersObject instanceof org.dom4j.Document) { List<Header> soapHeaders = new ArrayList<Header>(); try { DOMResult result = new DOMResult(); TransformerFactory.newInstance().newTransformer() .transform(new org.dom4j.io.DocumentSource((org.dom4j.Document) soapHeadersObject), result); for (Node node = ((Document) result.getNode()).getDocumentElement() .getFirstChild(); node != null; node = node.getNextSibling()) { if (Node.ELEMENT_NODE == node.getNodeType()) { soapHeaders.add(new Header(new QName(node.getNamespaceURI(), node.getLocalName()), node)); } } } catch (Exception e) { LOG.log(Level.SEVERE, "Uncaught exception during SOAP headers transformation: ", e); } } else if (soapHeadersObject instanceof List) { return (List<Header>) soapHeadersObject; } } return null; } private static boolean getBoolean(Map<String, Object> props, String propName) { Object propValue = props.get(propName); return (null == propValue) ? false : (Boolean) propValue; } private static void ensureServiceRegistryAvailable(Bus bus) { //for TESB-9006, update extensions when registry enabled but no wsdl-client/policy-client //extension set on the old bus. (used to instead the action of refresh job controller bundle. if (!bus.hasExtensionByName(WSDL_CLIENT_EXTENSION_NAME) || !bus.hasExtensionByName(POLICY_CLIENT_EXTENSION_NAME)) { boolean updated = false; Map<String, Extension> exts = ExtensionRegistry.getRegisteredExtensions(); updated |= setExtensionOnBusIfMissing(bus, exts, WSDL_CLIENT_EXTENSION_NAME); updated |= setExtensionOnBusIfMissing(bus, exts, POLICY_CLIENT_EXTENSION_NAME); if (updated) { // this should cause FactoryBeanListenerManager to refresh its list of event listeners FactoryBeanListenerManager fblm = bus.getExtension(FactoryBeanListenerManager.class); if (fblm != null) { fblm.setBus(bus); } else { throw new RuntimeException("CXF bus doesn't contain FactoryBeanListenerManager."); } } } } private static boolean setExtensionOnBusIfMissing(Bus bus, Map<String, Extension> exts, String extensionName) { if (exts.containsKey(extensionName) && !bus.hasExtensionByName(extensionName)) { ExtensionManager extMan = bus.getExtension(ExtensionManager.class); if (extMan instanceof ExtensionManagerImpl) { ((ExtensionManagerImpl) extMan).add(exts.get(extensionName)); return true; } else { throw new RuntimeException( "A required extension '" + extensionName + "' is not loaded on the CXF bus used by Job Controller. " + "In the same time, the bus uses unknown implementation of ExtensionManager, " + "so it is not possible to set the extension automatically."); } } return false; } }