/* * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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. */ package org.apache.synapse.transport.nhttp.config; import org.apache.axiom.om.OMElement; import org.apache.axis2.AxisFault; import org.apache.axis2.description.Parameter; import org.apache.axis2.description.TransportOutDescription; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpHost; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.synapse.transport.http.conn.ProxyConfig; import org.apache.synapse.transport.http.conn.ProxyProfileConfig; import org.apache.synapse.transport.passthru.PassThroughConstants; import javax.xml.namespace.QName; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; public class ProxyConfigBuilder { private HttpHost proxy; private UsernamePasswordCredentials proxyCredentials; private String[] proxyBypass; private String name; private static final QName Q_PROFILE = new QName("profile"); private static final QName Q_TARGET_HOSTS = new QName("targetHosts"); private static final QName Q_PROXY_HOST = new QName("proxyHost"); private static final QName Q_PROXY_PORT = new QName("proxyPort"); private static final QName Q_PROXY_USER = new QName("proxyUserName"); private static final QName Q_PROXY_PASSWORD = new QName("proxyPassword"); private static final QName Q_BYPASS = new QName("bypass"); private static final Log log = LogFactory.getLog(ProxyConfigBuilder.class); /** * Tries to read the axis2.xml transport sender's proxy configuration * @param transportOut axis2 transport out description * @return ProxyConfig * @throws AxisFault */ public ProxyConfig build(TransportOutDescription transportOut) throws AxisFault { name = transportOut.getName(); Map<String, ProxyProfileConfig> proxyProfileConfigMap = getProxyProfiles(transportOut); // if proxy profile is not configured, we read the proxy configured using http.proxyHost // if proxy profile is configured we only read profile related configuration if (proxyProfileConfigMap == null) { String proxyHost = null; int proxyPort = -1; Parameter proxyHostParam = transportOut.getParameter(PassThroughConstants.HTTP_PROXY_HOST); if (proxyHostParam != null) { proxyHost = (String) proxyHostParam.getValue(); Parameter proxyPortParam = transportOut.getParameter(PassThroughConstants.HTTP_PROXY_PORT); if (proxyPortParam != null) { proxyPort = Integer.parseInt((String) proxyPortParam.getValue()); } } if (proxyHost == null) { proxyHost = System.getProperty(PassThroughConstants.HTTP_PROXY_HOST); if (proxyHost != null) { String s = System.getProperty(PassThroughConstants.HTTP_PROXY_PORT); if (s != null) { proxyPort = Integer.parseInt(s); } } } if (proxyHost != null) { proxy = new HttpHost(proxyHost, proxyPort >= 0 ? proxyPort : 80); String bypassListStr = null; Parameter bypassListParam = transportOut.getParameter(PassThroughConstants.HTTP_NON_PROXY_HOST); if (bypassListParam == null) { bypassListStr = System.getProperty(PassThroughConstants.HTTP_NON_PROXY_HOST); } else { bypassListStr = (String) bypassListParam.getValue(); } if (bypassListStr != null) { proxyBypass = bypassListStr.split("\\|"); } Parameter proxyUsernameParam = transportOut.getParameter(PassThroughConstants.HTTP_PROXY_USERNAME); Parameter proxyPasswordParam = transportOut.getParameter(PassThroughConstants.HTTP_PROXY_PASSWORD); if (proxyUsernameParam != null) { proxyCredentials = new UsernamePasswordCredentials((String) proxyUsernameParam.getValue(), proxyPasswordParam != null ? (String) proxyPasswordParam.getValue() : ""); } } } return new ProxyConfig(proxy, proxyCredentials, proxyBypass, proxyProfileConfigMap); } /** * Looks for a transport parameter named proxyProfiles and initializes a map of ProxyProfileConfig. * The syntax for defining a proxy profiles is as follows. * {@code * <parameter name="proxyProfiles"> * <profile> * <targetHosts>example.com, *.sample.com</targetHosts> * <proxyHost>localhost</proxyHost> * <proxyPort>3128</proxyPort> * <proxyUserName>squidUser</proxyUserName> * <proxyPassword>password</proxyPassword> * <bypass>xxx.sample.com</bypass> * </profile> * <profile> * <targetHosts>localhost</targetHosts> * <proxyHost>localhost</proxyHost> * <proxyPort>7443</proxyPort> * </profile> * <profile> * <targetHosts>*</targetHosts> * <proxyHost>localhost</proxyHost> * <proxyPort>7443</proxyPort> * <bypass>test.com, direct.com</bypass> * </profile> * </parameter> * } * * @param transportOut transport out description * @return map of <code>ProxyProfileConfig<code/> if configured in axis2.xml; otherwise null * @throws AxisFault if proxy profile is not properly configured */ private Map<String, ProxyProfileConfig> getProxyProfiles(TransportOutDescription transportOut) throws AxisFault { Parameter proxyProfilesParam = transportOut.getParameter("proxyProfiles"); if (proxyProfilesParam == null) { return null; } if (log.isDebugEnabled()) { log.debug(name + " Loading proxy profiles for the HTTP/S sender"); } OMElement proxyProfilesParamEle = proxyProfilesParam.getParameterElement(); Iterator<?> profiles = proxyProfilesParamEle.getChildrenWithName(Q_PROFILE); Map<String, ProxyProfileConfig> proxyProfileMap = new HashMap<String, ProxyProfileConfig>(); while (profiles.hasNext()) { OMElement profile = (OMElement) profiles.next(); OMElement targetHostsEle = profile.getFirstChildWithName(Q_TARGET_HOSTS); if (targetHostsEle == null || targetHostsEle.getText().isEmpty()) { String msg = "Each proxy profile must define at least one host " + "or a wildcard matcher under the targetHosts element"; log.error(name + " " + msg); throw new AxisFault(msg); } HttpHost proxy = getHttpProxy(profile, targetHostsEle.getText()); UsernamePasswordCredentials proxyCredentials = getUsernamePasswordCredentials(profile); Set<String> proxyBypass = getProxyBypass(profile); ProxyProfileConfig proxyProfileConfig = new ProxyProfileConfig(proxy, proxyCredentials, proxyBypass); String[] targetHosts = targetHostsEle.getText().split(","); for (String endpoint : targetHosts) { endpoint = endpoint.trim(); if (!proxyProfileMap.containsKey(endpoint)) { proxyProfileMap.put(endpoint, proxyProfileConfig); } else { log.warn(name + " Multiple proxy profiles were found for the endpoint: " + endpoint + ". Ignoring the excessive profiles."); } } } if (proxyProfileMap.size() > 0) { log.info(name + " Proxy profiles initialized for " + proxyProfileMap.size() + " targetHosts"); return proxyProfileMap; } return null; } /** * Extracts the proxy server detail from given profile * @param profile profile element * @param targetHosts targetHosts given in the profile * @return proxyServer(HttpHost) configured in the given profile element * @throws AxisFault, if host or port element is not configured properly */ private HttpHost getHttpProxy(OMElement profile, String targetHosts) throws AxisFault { String proxyHost; String proxyPortStr; OMElement proxyHostEle = profile.getFirstChildWithName(Q_PROXY_HOST); if (proxyHostEle != null) { proxyHost = proxyHostEle.getText(); OMElement proxyPortEle = profile.getFirstChildWithName(Q_PROXY_PORT); if (proxyPortEle != null) { proxyPortStr = proxyPortEle.getText(); } else { throw new AxisFault("Proxy Port didn't configure correctly in proxy profile [" + targetHosts + "]"); } } else { throw new AxisFault("Proxy Host didn't configure correctly in proxy profile [" + targetHosts + "]"); } int proxyPort = Integer.parseInt(proxyPortStr); return new HttpHost(proxyHost, proxyPort >= 0 ? proxyPort : 80); } /** * Extracts the credential from given profile * @param profile profile element * @return usernamePasswordCredentials if username, password is configured, null otherwise */ private UsernamePasswordCredentials getUsernamePasswordCredentials(OMElement profile) { UsernamePasswordCredentials proxyCredentials = null; OMElement proxyUserNameEle = profile.getFirstChildWithName(Q_PROXY_USER); if (proxyUserNameEle != null) { String proxyUserName = proxyUserNameEle.getText(); OMElement proxyPasswordEle = profile.getFirstChildWithName(Q_PROXY_PASSWORD); String proxyPassword = proxyPasswordEle != null ? proxyPasswordEle.getText() : ""; proxyCredentials = new UsernamePasswordCredentials(proxyUserName, proxyPassword != null ? proxyPassword : ""); } return proxyCredentials; } /** * Extracts the proxyBypass hosts from given profile * @param profile profile element * @return Set of String containing bypass hosts; empty set if bypass hosts is not configured */ private Set<String> getProxyBypass(OMElement profile) { Set<String> bypassSet = new HashSet<String>(); OMElement bypassEle = profile.getFirstChildWithName(Q_BYPASS); if (bypassEle != null && !bypassEle.getText().isEmpty()) { String[] bypassHosts = bypassEle.getText().split(","); for (String bypassHost : bypassHosts) { bypassSet.add(bypassHost.trim()); } } return bypassSet; } }