/*
* Copyright (c) Members of the EGEE Collaboration. 2006-2010.
* See http://www.eu-egee.org/partners/ for details on the copyright holders.
*
* 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.
*/
package org.glite.authz.common.config;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import org.glite.voms.PKIStore;
import org.ini4j.Ini;
import org.opensaml.ws.soap.client.http.HttpClientBuilder;
import org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for configuration parsers that employ an INI file.
*
* @param <ConfigurationType> the type of configuration produced by this parser
*/
public abstract class AbstractIniServiceConfigurationParser<ConfigurationType extends AbstractServiceConfiguration>
extends AbstractIniConfigurationParser<ConfigurationType> {
/** The name of the {@value} INI header which contains the property for configuring the service. */
public static final String SERVICE_SECTION_HEADER = "SERVICE";
/** The name of the {@value} property which indicates the unique identity of the service. */
public static final String ENTITY_ID_PROP = "entityId";
/** The name of the {@value} property which indicates the service hostname. */
public static final String HOST_PROP = "hostname";
/** The name of the {@value} property which indicates the port to which the service will bind. */
public static final String PORT_PROP = "port";
/** The name of the {@value} property which indicates that the service port should use SSL instead of plain HTTP. */
public static final String SSL_ON_PORT_PROP = "enableSSL";
/** The name of the {@value} property which indicates that client certificate authentication is required. */
public static final String CLIENT_CERT_AUTHN_PROP = "requireClientCertAuthentication";
/** The name of the {@value} property which indicates the host the service will listen on for admin commands. */
public static final String ADMIN_HOST_PROP = "adminHost";
/** Default value of the {@value #ADMIN_HOST_PROP} property: {@value} . */
public static final String DEFAULT_ADMIN_HOST = "localhost";
/** The name of the {@value} property which indicates the port the service will listen on for admin commands. */
public static final String ADMIN_PORT_PROP = "adminPort";
/** The name of the {@value} property which indicates the password required for admin commands. */
public static final String ADMIN_PASSWORD_PROP = "adminPassword";
/** The name of the {@value} property which indicates the maximum number of requests that will be queued up. */
public static final String REQUEST_QUEUE_PROP = "requestQueueSize";
/** Default value of the {@value #SSL_ON_PORT_PROP} property, {@value} . */
public static final boolean DEFAULT_SSL_ON_PROP = false;
/** Default value of the {@value #CLIENT_CERT_AUTHN_PROP} property, {@value} . */
public static final boolean DEFAULT_CLIENT_CERT_AUTH = false;
/** Default value of the {@value #REQUEST_QUEUE_PROP} property, {@value} . */
public static final int DEFAULT_REQUEST_QUEUE = 500;
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(AbstractIniServiceConfigurationParser.class);
/**
* Gets the value of the {@value #ENTITY_ID_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*
* @throws ConfigurationException thrown if the entity ID property is not set or has an empty value
*/
protected String getEntityId(Ini.Section configSection) throws ConfigurationException {
return IniConfigUtil.getString(configSection, ENTITY_ID_PROP);
}
/**
* Gets the value of the {@value #HOST_PROP} property from the configuration section. If the property is not present
* or is not valid the default value of {@value #DEFAULT_HOST} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*
* @throws ConfigurationException thrown if no host name is given
*/
protected String getHostname(Ini.Section configSection) throws ConfigurationException {
return IniConfigUtil.getString(configSection, HOST_PROP);
}
/**
* Gets the value of the {@value #PORT_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return the value, or 0 if it is not set
*/
protected int getPort(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, PORT_PROP, 0, 1, 65535);
}
/**
* Gets the value of the {@value #SSL_ON_PORT_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return whether SSL should be enabled on the service port, defaults to {@value #DEFAULT_SSL_ON_PROP}.
*/
protected boolean isSSLEnabled(Ini.Section configSection) {
if (configSection == null)
return DEFAULT_SSL_ON_PROP;
if (configSection.containsKey(SERVICE_KEY_PROP) && configSection.containsKey(SERVICE_CERT_PROP)
&& configSection.containsKey(TRUST_INFO_DIR_PROP)) {
return IniConfigUtil.getBoolean(configSection, SSL_ON_PORT_PROP, DEFAULT_SSL_ON_PROP);
} else {
return DEFAULT_SSL_ON_PROP;
}
}
/**
* Gets the value of the {@value #CLIENT_CERT_AUTHN_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return whether client certificate authentication is required when a client is connecting, defaults to
* {@value #DEFAULT_CLIENT_CERT_AUTH}.
*/
protected boolean isClientCertAuthRequired(Ini.Section configSection) {
if (configSection == null)
return DEFAULT_CLIENT_CERT_AUTH;
if (isSSLEnabled(configSection)) {
return IniConfigUtil.getBoolean(configSection, CLIENT_CERT_AUTHN_PROP, DEFAULT_CLIENT_CERT_AUTH);
} else {
return DEFAULT_CLIENT_CERT_AUTH;
}
}
/**
* Gets the value of the {@value #ADMIN_HOST_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return the admin host value, or the default admin host {@value #DEFAULT_ADMIN_HOST} if it is not set
*/
protected String getAdminHost(Ini.Section configSection) {
return IniConfigUtil.getString(configSection, ADMIN_HOST_PROP, DEFAULT_ADMIN_HOST);
}
/**
* Gets the value of the {@value #ADMIN_PORT_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return the value, or 0 if is not set
*/
protected int getAdminPort(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, ADMIN_PORT_PROP, 0, 1, 65535);
}
/**
* Gets the value of the {@value #ADMIN_PASSWORD_PROP} property from the configuration section.
*
* @param configSection configuration section from which to extract the value
*
* @return the value or null if it is not set
*/
protected String getAdminPassword(Ini.Section configSection) {
return IniConfigUtil.getString(configSection, ADMIN_PASSWORD_PROP, null);
}
/**
* Gets the value of the {@value #REQUEST_QUEUE_PROP} property from the configuration section. If the property is
* not present or is not valid the default value of {@value #DEFAULT_REQUEST_QUEUE} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getMaxRequestQueueSize(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, REQUEST_QUEUE_PROP, DEFAULT_REQUEST_QUEUE, 1, Integer.MAX_VALUE);
}
/**
* Process the information contained in the {@value #SERVICE_SECTION_HEADER} configuration section.
*
* @param iniFile INI file being processed
* @param configBuilder builder being populated with configuration information
*
* @throws ConfigurationException thrown if there is a problem reading the information contained in the
* {@value #SERVICE_SECTION_HEADER} section
*/
protected void processServiceSection(Ini iniFile, AbstractServiceConfigurationBuilder<?> configBuilder)
throws ConfigurationException {
Ini.Section configSection = iniFile.get(SERVICE_SECTION_HEADER);
if (configSection == null) {
String errorMsg = "INI configuration does not contain the required '" + SERVICE_SECTION_HEADER
+ "' INI section";
log.error(errorMsg);
throw new ConfigurationException(errorMsg);
}
String name= configSection.getName();
String entityId = getEntityId(configSection);
log.info("{}: entity ID: {}", name,entityId);
configBuilder.setEntityId(entityId);
String host = getHostname(configSection);
log.info("{}: service hostname: {}", name,host);
configBuilder.setHost(host);
int port = getPort(configSection);
log.info("{}: service port: {}", name,port);
configBuilder.setPort(port);
String adminHost = getAdminHost(configSection);
log.info("{}: service admin hostname: {}", name,adminHost == null ? "default" : adminHost);
configBuilder.setAdminHost(adminHost);
int adminPort = getAdminPort(configSection);
log.info("{}: service admin port: {}", name,adminPort == 0 ? "default" : adminPort);
configBuilder.setAdminPort(adminPort);
String adminPassword = getAdminPassword(configSection);
log.info("{}: service admin password set: {}", name,adminPassword == null ? "no" : "yes");
configBuilder.setAdminPassword(adminPassword);
int maxConnections = getMaximumRequests(configSection);
log.info("{}: max requests: {}", name,maxConnections);
configBuilder.setMaxConnections(maxConnections);
int connTimeout = getConnectionTimeout(configSection);
log.info("{}: connection timeout: {}ms", name,connTimeout);
configBuilder.setConnectionTimeout(connTimeout);
int maxReqQueue = getMaxRequestQueueSize(configSection);
log.info("{}: max request queue size: {}", name,maxReqQueue);
configBuilder.setMaxRequestQueueSize(maxReqQueue);
int receiveBuffer = getReceiveBufferSize(configSection);
log.info("{}: recieve buffer size: {} bytes", name,receiveBuffer);
configBuilder.setReceiveBufferSize(receiveBuffer);
int sendBuffer = getSendBufferSize(configSection);
log.info("{}: send buffer size: {} bytes", name,sendBuffer);
configBuilder.setSendBufferSize(sendBuffer);
}
/**
* Process the information contained in the {@value #SECURITY_SECTION_HEADER} configuration section.
*
* @param iniFile INI file being processed
* @param configBuilder builder being populated with configuration information
*
* @throws ConfigurationException thrown if there is a problem reading the information contained in the
* {@value #SECURITY_SECTION_HEADER} section
*/
protected void processSecuritySection(Ini iniFile, AbstractServiceConfigurationBuilder<?> configBuilder)
throws ConfigurationException {
Ini.Section securityConfig = iniFile.get(SECURITY_SECTION_HEADER);
if (securityConfig==null) {
log.warn("INI configuration does not contain the '{}' section", SECURITY_SECTION_HEADER);
}
String name= securityConfig.getName();
X509KeyManager x509KeyManager= getX509KeyManager(securityConfig);
configBuilder.setKeyManager(x509KeyManager);
PKIStore pkiStore= getX509TrustMaterialStore(securityConfig);
configBuilder.setX509TrustMaterial(pkiStore);
boolean sslOn = isSSLEnabled(securityConfig);
log.info("{}: service port using SSL: {}", name,sslOn);
configBuilder.setSslEnabled(sslOn);
boolean clientCertAuthRequired = isClientCertAuthRequired(securityConfig);
log.info("{}: TLS client certificate authentication required: {}", name,clientCertAuthRequired);
configBuilder.setClientCertAuthRequired(clientCertAuthRequired);
}
/**
* Builds a SOAP client builder from the information contained in the configuration section.
*
* @param configSection client configuration
* @param keyManager key manager used for outbound SSL/TLS connections
* @param trustManager trust manager used for inbound SSL/TLS connections
*
* @return the constructed SOAP client
*/
protected HttpClientBuilder buildSOAPClientBuilder(Ini.Section configSection, X509KeyManager keyManager,
X509TrustManager trustManager) {
HttpClientBuilder httpClientBuilder = new HttpClientBuilder();
httpClientBuilder.setContentCharSet("UTF-8");
String name= configSection.getName();
int conTimeout = getConnectionTimeout(configSection);
log.info("{}: connection timeout: {}ms", name,conTimeout);
httpClientBuilder.setConnectionTimeout(conTimeout);
int maxRequests = getMaximumRequests(configSection);
log.info("{}: maximum requests: {}", name,maxRequests);
httpClientBuilder.setMaxTotalConnections(maxRequests);
httpClientBuilder.setMaxConnectionsPerHost(maxRequests);
int recBuffSize = getSendBufferSize(configSection);
log.info("{}: recieve buffer size: {} bytes", name,recBuffSize);
httpClientBuilder.setReceiveBufferSize(recBuffSize);
int sendBuffSize = getSendBufferSize(configSection);
log.info("{}: send buffer size: {} bytes", name,sendBuffSize);
httpClientBuilder.setSendBufferSize(sendBuffSize);
if (keyManager != null && trustManager != null) {
log.debug("adding configured X509 key & trust manager to SOAP client");
TLSProtocolSocketFactory factory = new TLSProtocolSocketFactory(keyManager, trustManager);
httpClientBuilder.setHttpsProtocolSocketFactory(factory);
}
return httpClientBuilder;
}
}