| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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.ftpserver.config.spring; |
| |
| import java.net.UnknownHostException; |
| |
| import org.apache.ftpserver.DataConnectionConfiguration; |
| import org.apache.ftpserver.DataConnectionConfigurationFactory; |
| import org.apache.ftpserver.FtpServerConfigurationException; |
| import org.apache.ftpserver.ipfilter.IpFilterType; |
| import org.apache.ftpserver.ipfilter.RemoteIpFilter; |
| import org.apache.ftpserver.listener.ListenerFactory; |
| import org.apache.ftpserver.ssl.SslConfiguration; |
| import org.apache.ftpserver.ssl.SslConfigurationFactory; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.beans.factory.config.BeanDefinition; |
| import org.springframework.beans.factory.config.BeanDefinitionHolder; |
| import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
| import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; |
| import org.springframework.beans.factory.xml.ParserContext; |
| import org.springframework.util.StringUtils; |
| import org.w3c.dom.Element; |
| |
| /** |
| * Parses the FtpServer "nio-listener" element into a Spring bean graph |
| * |
| * @author <a href="http://mina.apache.org">Apache MINA Project</a> |
| */ |
| public class ListenerBeanDefinitionParser extends |
| AbstractSingleBeanDefinitionParser { |
| |
| private final Logger LOG = LoggerFactory |
| .getLogger(ListenerBeanDefinitionParser.class); |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected Class<?> getBeanClass(final Element element) { |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void doParse(final Element element, |
| final ParserContext parserContext, |
| final BeanDefinitionBuilder builder) { |
| |
| BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ListenerFactory.class); |
| |
| if (StringUtils.hasText(element.getAttribute("port"))) { |
| factoryBuilder.addPropertyValue("port", Integer.valueOf(element |
| .getAttribute("port"))); |
| } |
| |
| SslConfiguration ssl = parseSsl(element); |
| if (ssl != null) { |
| factoryBuilder.addPropertyValue("sslConfiguration", ssl); |
| } |
| |
| Element dataConElm = SpringUtil.getChildElement(element, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "data-connection"); |
| DataConnectionConfiguration dc = parseDataConnection(dataConElm, ssl); |
| factoryBuilder.addPropertyValue("dataConnectionConfiguration", dc); |
| |
| if (StringUtils.hasText(element.getAttribute("idle-timeout"))) { |
| factoryBuilder.addPropertyValue("idleTimeout", SpringUtil.parseInt( |
| element, "idle-timeout", 300)); |
| } |
| |
| String localAddress = SpringUtil.parseStringFromInetAddress(element, |
| "local-address"); |
| if (localAddress != null) { |
| factoryBuilder.addPropertyValue("serverAddress", localAddress); |
| } |
| factoryBuilder.addPropertyValue("implicitSsl", SpringUtil.parseBoolean( |
| element, "implicit-ssl", false)); |
| |
| Element blacklistElm = SpringUtil.getChildElement(element, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "blacklist"); |
| if (blacklistElm != null) { |
| LOG |
| .warn("Element 'blacklist' is deprecated, and may be removed in a future release. Please use 'remote-ip-filter' instead. "); |
| try { |
| RemoteIpFilter remoteIpFilter = new RemoteIpFilter(IpFilterType.DENY, |
| blacklistElm.getTextContent()); |
| factoryBuilder.addPropertyValue("sessionFilter", remoteIpFilter); |
| } catch (UnknownHostException e) { |
| throw new IllegalArgumentException( |
| "Invalid IP address or subnet in the 'blacklist' element", |
| e); |
| } |
| } |
| |
| Element remoteIpFilterElement = SpringUtil.getChildElement(element, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "remote-ip-filter"); |
| if (remoteIpFilterElement != null) { |
| if (blacklistElm != null) { |
| throw new FtpServerConfigurationException( |
| "Element 'remote-ip-filter' may not be used when 'blacklist' element is specified. "); |
| } |
| String filterType = remoteIpFilterElement.getAttribute("type"); |
| try { |
| RemoteIpFilter remoteIpFilter = new RemoteIpFilter(IpFilterType |
| .parse(filterType), remoteIpFilterElement |
| .getTextContent()); |
| factoryBuilder |
| .addPropertyValue("sessionFilter", remoteIpFilter); |
| } catch (UnknownHostException e) { |
| throw new IllegalArgumentException( |
| "Invalid IP address or subnet in the 'remote-ip-filter' element"); |
| } |
| } |
| |
| BeanDefinition factoryDefinition = factoryBuilder.getBeanDefinition(); |
| |
| String listenerFactoryName = parserContext.getReaderContext().generateBeanName(factoryDefinition); |
| |
| BeanDefinitionHolder factoryHolder = new BeanDefinitionHolder(factoryDefinition, listenerFactoryName); |
| registerBeanDefinition(factoryHolder, parserContext.getRegistry()); |
| |
| // set the factory on the listener bean |
| builder.getRawBeanDefinition().setFactoryBeanName(listenerFactoryName); |
| builder.getRawBeanDefinition().setFactoryMethodName("createListener"); |
| } |
| |
| private SslConfiguration parseSsl(final Element parent) { |
| Element sslElm = SpringUtil.getChildElement(parent, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "ssl"); |
| |
| if (sslElm != null) { |
| SslConfigurationFactory ssl = new SslConfigurationFactory(); |
| |
| Element keyStoreElm = SpringUtil.getChildElement(sslElm, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "keystore"); |
| if (keyStoreElm != null) { |
| ssl.setKeystoreFile(SpringUtil.parseFile(keyStoreElm, "file")); |
| ssl.setKeystorePassword(SpringUtil.parseString(keyStoreElm, |
| "password")); |
| |
| String type = SpringUtil.parseString(keyStoreElm, "type"); |
| if (type != null) { |
| ssl.setKeystoreType(type); |
| } |
| |
| String keyAlias = SpringUtil.parseString(keyStoreElm, |
| "key-alias"); |
| if (keyAlias != null) { |
| ssl.setKeyAlias(keyAlias); |
| } |
| |
| String keyPassword = SpringUtil.parseString(keyStoreElm, |
| "key-password"); |
| if (keyPassword != null) { |
| ssl.setKeyPassword(keyPassword); |
| } |
| |
| String algorithm = SpringUtil.parseString(keyStoreElm, |
| "algorithm"); |
| if (algorithm != null) { |
| ssl.setKeystoreAlgorithm(algorithm); |
| } |
| } |
| |
| Element trustStoreElm = SpringUtil.getChildElement(sslElm, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "truststore"); |
| if (trustStoreElm != null) { |
| ssl.setTruststoreFile(SpringUtil.parseFile(trustStoreElm, |
| "file")); |
| ssl.setTruststorePassword(SpringUtil.parseString(trustStoreElm, |
| "password")); |
| |
| String type = SpringUtil.parseString(trustStoreElm, "type"); |
| if (type != null) { |
| ssl.setTruststoreType(type); |
| } |
| |
| String algorithm = SpringUtil.parseString(trustStoreElm, |
| "algorithm"); |
| if (algorithm != null) { |
| ssl.setTruststoreAlgorithm(algorithm); |
| } |
| } |
| |
| String clientAuthStr = SpringUtil.parseString(sslElm, |
| "client-authentication"); |
| if (clientAuthStr != null) { |
| ssl.setClientAuthentication(clientAuthStr); |
| } |
| |
| String enabledCiphersuites = SpringUtil.parseString(sslElm, |
| "enabled-ciphersuites"); |
| if (enabledCiphersuites != null) { |
| ssl.setEnabledCipherSuites(enabledCiphersuites.split(" ")); |
| } |
| |
| String protocol = SpringUtil.parseString(sslElm, "protocol"); |
| if (protocol != null) { |
| ssl.setSslProtocol(protocol); |
| } |
| |
| return ssl.createSslConfiguration(); |
| } else { |
| return null; |
| } |
| |
| } |
| |
| private DataConnectionConfiguration parseDataConnection( |
| final Element element, |
| final SslConfiguration listenerSslConfiguration) { |
| DataConnectionConfigurationFactory dc = new DataConnectionConfigurationFactory(); |
| |
| if (element != null) { |
| |
| dc.setImplicitSsl(SpringUtil.parseBoolean(element, "implicit-ssl", false)); |
| |
| // data con config element available |
| SslConfiguration ssl = parseSsl(element); |
| |
| if (ssl != null) { |
| LOG.debug("SSL configuration found for the data connection"); |
| dc.setSslConfiguration(ssl); |
| } |
| |
| dc.setIdleTime(SpringUtil.parseInt(element, "idle-timeout", dc.getIdleTime())); |
| |
| Element activeElm = SpringUtil.getChildElement(element, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "active"); |
| if (activeElm != null) { |
| dc.setActiveEnabled(SpringUtil.parseBoolean(activeElm, "enabled", |
| true)); |
| dc.setActiveIpCheck(SpringUtil.parseBoolean(activeElm, |
| "ip-check", false)); |
| dc.setActiveLocalPort(SpringUtil.parseInt(activeElm, |
| "local-port", 0)); |
| |
| String localAddress = SpringUtil.parseStringFromInetAddress( |
| activeElm, "local-address"); |
| if (localAddress != null) { |
| dc.setActiveLocalAddress(localAddress); |
| } |
| } |
| |
| Element passiveElm = SpringUtil.getChildElement(element, |
| FtpServerNamespaceHandler.FTPSERVER_NS, "passive"); |
| if (passiveElm != null) { |
| String address = SpringUtil.parseStringFromInetAddress(passiveElm, |
| "address"); |
| if (address != null) { |
| dc.setPassiveAddress(address); |
| } |
| |
| String externalAddress = SpringUtil.parseStringFromInetAddress( |
| passiveElm, "external-address"); |
| if (externalAddress != null) { |
| dc.setPassiveExternalAddress(externalAddress); |
| } |
| |
| String ports = SpringUtil.parseString(passiveElm, "ports"); |
| if (ports != null) { |
| dc.setPassivePorts(ports); |
| } |
| dc.setPassiveIpCheck(SpringUtil.parseBoolean(passiveElm, |
| "ip-check", false)); |
| } |
| } else { |
| // no data conn config element, do we still have SSL config from the |
| // parent? |
| if (listenerSslConfiguration != null) { |
| LOG |
| .debug("SSL configuration found for the listener, falling back for that for the data connection"); |
| dc.setSslConfiguration(listenerSslConfiguration); |
| } |
| } |
| |
| return dc.createDataConnectionConfiguration(); |
| } |
| |
| } |