/*
* 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 java.io.IOException;
import javax.net.ssl.X509KeyManager;
import net.jcip.annotations.ThreadSafe;
import org.glite.authz.common.util.Files;
import org.glite.security.trustmanager.ContextWrapper;
import org.glite.security.trustmanager.UpdatingKeyManager;
import org.glite.security.util.CaseInsensitiveProperties;
import org.glite.voms.PKIStore;
import org.ini4j.Ini;
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
*/
@ThreadSafe
public abstract class AbstractIniConfigurationParser<ConfigurationType extends AbstractConfiguration> implements
ConfigurationParser<ConfigurationType> {
/** The name of the {@value} INI header which contains the property for configuring credential/trust information. */
public static final String SECURITY_SECTION_HEADER = "SECURITY";
/** The name of the {@value} which gives the path to the service's private key. */
public static final String SERVICE_KEY_PROP = "servicePrivateKey";
/** The name of the {@value} which gives the path to the service's certificate. */
public static final String SERVICE_CERT_PROP = "serviceCertificate";
/** The name of the {@value} which gives the path to directory of PEM-encoded trusted X.509 certificates. */
public static final String TRUST_INFO_DIR_PROP = "trustInfoDir";
/** The name of the {@value} which gives the refresh period, in minutes, for the trust information. */
public static final String TRUST_INFO_REFRSH_PROP = "trustInfoRefresh";
/** The name of the {@value} which gives the maximum number of simultaneous requests. */
public static final String MAX_REQUESTS_PROP = "maximumRequests";
/** The name of the {@value} which gives the connection timeout, in seconds. */
public static final String CONN_TIMEOUT_PROP = "connectionTimeout";
/** The name of the {@value} which gives the size of the receiving message buffer, in bytes. */
public static final String REC_BUFF_SIZE_PROP = "receiveBufferSize";
/** The name of the {@value} which gives the sending message buffer, in bytes. */
public static final String SEND_BUFF_SIZE_PROP = "sendBufferSize";
/** Default value of the {@value #TRUST_INFO_REFRSH_PROP} property, {@value} . */
public static final int DEFAULT_TRUST_INFO_REFRESH = 60;
/** Default value of the {@value #MAX_REQUESTS_PROP} property, {@value} . */
public static final int DEFAULT_MAX_REQS = 200;
/** Default value of the {@value #CONN_TIMEOUT_PROP} property, {@value} seconds. */
public static final int DEFAULT_CONN_TIMEOUT = 30;
/** Default value of the {@value #REC_BUFF_SIZE_PROP} property, {@value} kilobytes. */
public static final int DEFAULT_REC_BUFF_SIZE = 16384;
/** Default value of the {@value #SEND_BUFF_SIZE_PROP} property, {@value} kilobytes. */
public static final int DEFAULT_SEND_BUFF_SIZE = 16384;
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(AbstractIniConfigurationParser.class);
/**
* Gets the value of the {@value #CONN_TIMEOUT_PROP} property from the configuration section. If the property is not
* present or is not valid the default value of {@value #DEFAULT_CONN_TIMEOUT} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getConnectionTimeout(Ini.Section configSection) {
int timeout = IniConfigUtil
.getInt(configSection, CONN_TIMEOUT_PROP, DEFAULT_CONN_TIMEOUT, 1, Integer.MAX_VALUE);
return timeout * 1000;
}
/**
* Gets the value of the {@value #MAX_REQUESTS_PROP} property from the configuration section. If the property is not
* present or is not valid the default value of {@value #DEFAULT_MAX_REQS} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getMaximumRequests(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, MAX_REQUESTS_PROP, DEFAULT_MAX_REQS, 1, Integer.MAX_VALUE);
}
/**
* Gets the value of the {@value #REC_BUFF_SIZE_PROP} property from the configuration section. If the property is
* not present or is not valid the default value of {@value #DEFAULT_REC_BUFF_SIZE} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getReceiveBufferSize(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, REC_BUFF_SIZE_PROP, DEFAULT_REC_BUFF_SIZE, 1, Integer.MAX_VALUE);
}
/**
* Gets the value of the {@value #SEND_BUFF_SIZE_PROP} property from the configuration section. If the property is
* not present or is not valid the default value of {@value #DEFAULT_SEND_BUFF_SIZE} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getSendBufferSize(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, SEND_BUFF_SIZE_PROP, DEFAULT_SEND_BUFF_SIZE, 1, Integer.MAX_VALUE);
}
/**
* Gets the value of the {@value #TRUST_INFO_REFRSH_PROP} property from the configuration section. If the property
* is not present or is not valid the default value of {@value #DEFAULT_TRUST_INFO_REFRESH} will be used.
*
* @param configSection configuration section from which to extract the value
*
* @return the value
*/
protected int getTrustMaterialRefreshInterval(Ini.Section configSection) {
return IniConfigUtil.getInt(configSection, TRUST_INFO_REFRSH_PROP, DEFAULT_TRUST_INFO_REFRESH, 1,
Integer.MAX_VALUE);
}
/**
* Creates a {@link javax.net.ssl.KeyManager} from the {@value #SERVICE_KEY_PROP} and {@value #SERVICE_CERT_PROP}
* properties, if they exist.
*
* @param configSection current configuration section being processed
*
* @return the constructed key manager, or null if the required properties do not exist
*
* @throws ConfigurationException thrown if there is a problem creating the key manager
*/
protected X509KeyManager getX509KeyManager(Ini.Section configSection) throws ConfigurationException {
if (configSection == null) {
return null;
}
String name= configSection.getName();
String privateKeyFilePath = IniConfigUtil.getString(configSection, SERVICE_KEY_PROP, null);
if (privateKeyFilePath == null) {
log.info("{}: No service private key file provided, no service credential will be used.",name);
return null;
}
String certificateFilePath = IniConfigUtil.getString(configSection, SERVICE_CERT_PROP, null);
if (certificateFilePath == null) {
log.info("{}: No service certificate file provided, no service credential will be used.",name);
return null;
}
log.info("{}: service credential will use private key {} and certificate {}", new Object[] {name, privateKeyFilePath,
certificateFilePath});
CaseInsensitiveProperties keystoreProps = new CaseInsensitiveProperties();
keystoreProps.setProperty(ContextWrapper.CREDENTIALS_KEY_FILE, privateKeyFilePath);
keystoreProps.setProperty(ContextWrapper.CREDENTIALS_CERT_FILE, certificateFilePath);
try {
return new UpdatingKeyManager(keystoreProps, null);
} catch (Exception e) {
log.error("Unable to create service key manager", e);
throw new ConfigurationException("Unable to read service credential information", e);
}
}
/**
* Creates a {@link PKIStore} from the {@value #TRUST_INFO_DIR_PROP} property, if they exist. This store holds the
* material used to validate X.509 certificates.
*
* @param configSection current configuration section being processed
*
* @return the constructed trust material store, or null if the required attribute did not exist
*
* @throws ConfigurationException thrown if there is a problem creating the trust manager
*/
protected PKIStore getX509TrustMaterialStore(Ini.Section configSection) throws ConfigurationException {
if (configSection == null) {
return null;
}
String name= configSection.getName();
String trustStoreDir = IniConfigUtil.getString(configSection, TRUST_INFO_DIR_PROP, null);
if (trustStoreDir == null) {
log.info("{}: No truststore directory given, no trust manager will be used",name);
return null;
}
try {
Files.getFile(trustStoreDir, false, true, true, false);
} catch (IOException e) {
log.error("Unable to read truststore directory " + trustStoreDir, e);
throw new ConfigurationException(e.getMessage());
}
log.info("{}: X.509 trusted information directory: {}", name,trustStoreDir);
int refreshInterval = getTrustMaterialRefreshInterval(configSection) * 60 * 1000;
log.info("{}: trust information refresh interval: {}ms", name,refreshInterval);
try {
PKIStore trustMaterial = new PKIStore(trustStoreDir, PKIStore.TYPE_CADIR);
trustMaterial.rescheduleRefresh(refreshInterval);
return trustMaterial;
} catch (Exception e) {
log.error("Unable to create X.509 trust material store", e);
throw new ConfigurationException("Unable to create X.509 trust material store", e);
}
}
}