/* * Copyright 2003 Federal Chancellery Austria * MOA-SPSS has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moa.spss.server.config; import iaik.asn1.structures.Name; import iaik.pki.revocation.RevocationSourceTypes; import iaik.utils.RFC2253NameParser; import iaik.utils.RFC2253NameParserException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.net.URL; import java.security.Principal; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.w3c.dom.Element; import at.gv.egovernment.moa.spss.api.common.TSLConfiguration; import at.gv.egovernment.moa.spss.util.MessageProvider; import at.gv.egovernment.moaspss.logging.LogMsg; import at.gv.egovernment.moaspss.logging.Logger; import at.gv.egovernment.moaspss.util.DOMUtils; import at.gv.egovernment.moaspss.util.MiscUtil; /** * A class providing access to the MOA configuration data. * *

Configuration data is read from an XML file, whose location is given by * the moa.spss.server.configuration system property.

*

This class implements the Singleton pattern. The reload() * method can be used to update the configuration data. Therefore, it is not * guaranteed that consecutive calls to getInstance() will return * the same ConfigurationProvider all the time. During the * processing of a web service request, the current * TransactionContext should be used to obtain the * ConfigurationProvider local to that request.

* * @author Patrick Peck * @author Sven Aigner * @version $Id$ */ public class ConfigurationProvider { /** * The name of the system property which contains the file name of the * configuration file. */ public static final String CONFIG_PROPERTY_NAME = "moa.spss.server.configuration"; /** * A fake IssuerAndSerial object for storing KeyGroup information * accessible by all clients. */ private static final IssuerAndSerial ANONYMOUS_ISSUER_SERIAL = new IssuerAndSerial(new Name(), new BigInteger("0")); /** Singleton instance. null, if none has been created. */ private static ConfigurationProvider instance; // // configuration data // /** The warnings generated when building the configuration. */ private List warnings = new ArrayList(); /** The default digest method algorithm name */ private String digestMethodAlgorithmName; /** The default canonicalization algorithm name */ private String canonicalizationAlgorithmName; /** The XAdES version used for signature creation */ private String xadesVersion; /** PDF AS Configuration */ private String pdfAsConfiguration; private int connectionTimeout; private int readTimeout; /** * A List of HardwareCryptoModule objects for * configuring hardware modules. */ private List hardwareCryptoModules; /** * A List of HardwareKey objects containing the * configuration data for hardware keys. */ private List hardwareKeyModules; /** * A List of SoftwareKey objects containing the * configuration data for software keys. */ private List softwareKeyModules; /** * A Map which contains a KeyGroupId (a String) to * KeyGroup mapping. */ private Map keyGroups; /** * A Map which contains the IssuerAndSerial to * KeyGroup mapping. */ private Map keyGroupMappings; /** The default chaining mode. */ private String defaultChainingMode; /** * A Map which contains the IssuerAndSerial to * chaining mode (a String) mapping. */ private Map chainingModes; /** * A Map which contains the CAIssuerDN (a String) * to distribution points (a Set of * DistributionPoints) mapping. */ private Map distributionPoints; /** * The CRL archive duration. */ private int cRLArchiveDuration; /** * Indicates whether revocation information should be archived. */ private boolean enableRevocationArchiving_; /** * The location of the certificate store. */ private String certStoreLocation_; /** * A Map which contains a mapping from * CreateSignatureEnvironmentProfile Ids (String) to * CreateSignatureEnvironmentProfile elements (an Element). */ private Map createSignatureEnvironmentProfiles; /** * A Map which contains a mapping from * CreateTransformsInfoProfile Ids (String) to * CreateTransformsInfoProfile elements (an Element). */ private Map createTransformsInfoProfiles; /** * A Map which contains a mapping from * VerifyTransformsInfoProfile Ids (String) to * VerifyTransformsInfoProfile elements (an Element). */ private Map verifyTransformsInfoProfiles; /** * A Map which contains a mapping from * SupplementProfile Ids (String) to SupplementProfile elements * (an Element). */ private Map supplementProfiles; /** * A Map which contains a TrustProfile Id (a String * to trust profile (a TrustProfile) mapping. */ private Map trustProfiles; /** * The JDBC URL for the revocation archive database. */ private String revocationArchiveJDBCURL_; /** * The JDBC driver class name for the revocation archive database. */ private String revocationArchiveJDBCDriverClass_; /** * Indicates whether revocation checking should be done. */ private boolean enableRevocationChecking_; /** * The maximum age of a revocation information for considering it still as valid. */ private long maxRevocationAge_; /** * The service order for revocation checking. */ private String[] serviceOrder_; private boolean adesFormResults; /** * Indicates whether certificates found during certificate path construction * should be added to the certificate store. */ private boolean autoAddCertificates_; /** * Indicates whether the certificate extension Authority Info Access should * be used during certificate path construction. */ private boolean useAuthorityInfoAccess_; /** * Indicates whether file URIs are allowed or not */ private boolean permitFileURIs; /** * Indicates the CRL retention intervals */ private Map crlRetentionIntervals; /** * Indicates wether external URIs are allowed or not */ private boolean allowExternalUris_; /** * A List of black listed URIs (host and port) */ private List blackListedUris_; /** * A List of white listed URIs (host and port) */ private List whiteListedUris_; /** * A TSLConfiguration that represents the global TSL configuration */ private TSLConfiguration tslconfiguration_; /** * Return the single instance of configuration data. * * @return MOAConfigurationProvider The current configuration data. * @throws ConfigurationException Failure to load the configuration data. */ public static synchronized ConfigurationProvider getInstance() throws ConfigurationException { if (instance == null) { reload(); } return instance; } /** * Reload the configuration data and set it if successful. * * @return MOAConfigurationProvider The loaded configuration data. * @throws ConfigurationException Failure to load the configuration data. */ public static synchronized ConfigurationProvider reload() throws ConfigurationException { String fileName = System.getProperty(CONFIG_PROPERTY_NAME); if (fileName == null) { // find out where we are running and use the configuration provided // under WEB-INF/conf/moa-spss/MOA-SPSSConfiguration URL url = ConfigurationProvider.class.getResource("/"); fileName = new File(url.getPath()).getParent() + "/conf/moa-spss/MOA-SPSSConfiguration.xml"; info("config.05", new Object[] { CONFIG_PROPERTY_NAME }); } instance = new ConfigurationProvider(fileName); return instance; } /** * Constructor for ConfigurationProvider. * * @param fileName The name of the configuration file. * @throws ConfigurationException An error occurred loading the configuration. */ public ConfigurationProvider(String fileName) throws ConfigurationException { load(fileName); } /** * Load the configuration data from XML file with the given name and build * the internal data structures representing the MOA configuration. * * @param fileName The name of the XML file to load. * @throws ConfigurationException The MOA configuration could not be * read/built. */ private void load(String fileName) throws ConfigurationException { FileInputStream stream = null; File configFile; File configRoot; Element configElem; ConfigurationPartsBuilder builder; List allKeyModules; // load the main config file try { configFile = new File(fileName); configRoot = new File(configFile.getParent()); info("config.21", new Object[] { configFile.getAbsoluteFile()}); stream = new FileInputStream(fileName); configElem = DOMUtils.parseXmlValidating(new FileInputStream(fileName)); } catch (Throwable t) { throw new ConfigurationException("config.10", null, t); } // build the internal datastructures try { builder = new ConfigurationPartsBuilder(configElem, configRoot); //build TSL configuration tslconfiguration_ = builder.getTSLConfiguration(); //build TrustProfile configuration trustProfiles = builder.buildTrustProfiles(); //check TSL configuration checkTSLConfiguration(); digestMethodAlgorithmName = builder.getDigestMethodAlgorithmName(); canonicalizationAlgorithmName = builder.getCanonicalizationAlgorithmName(); hardwareCryptoModules = builder.buildHardwareCryptoModules(); hardwareKeyModules = builder.buildHardwareKeyModules(Collections.EMPTY_LIST); softwareKeyModules = builder.buildSoftwareKeyModules(hardwareKeyModules); allKeyModules = new ArrayList(hardwareKeyModules); allKeyModules.addAll(softwareKeyModules); keyGroups = builder.buildKeyGroups(allKeyModules); keyGroupMappings = builder.buildKeyGroupMappings(keyGroups, ANONYMOUS_ISSUER_SERIAL); connectionTimeout = builder.getConnectionTimeout(); readTimeout = builder.getReadTimeout(); pdfAsConfiguration = builder.getPDFASConfiguration(); adesFormResults = builder.getAdesFormResult(); xadesVersion = builder.getXAdESVersion(); defaultChainingMode = builder.getDefaultChainingMode(); chainingModes = builder.buildChainingModes(); useAuthorityInfoAccess_ = builder.getUseAuthorityInfoAccess(); autoAddCertificates_ = builder.getAutoAddCertificates(); //trustProfiles = builder.buildTrustProfiles(tslconfiguration_.getWorkingDirectory()); distributionPoints = builder.buildDistributionPoints(); enableRevocationChecking_ = builder.getEnableRevocationChecking(); maxRevocationAge_ = builder.getMaxRevocationAge(); serviceOrder_ = builder.getServiceOrder(); enableRevocationArchiving_ = builder.getEnableRevocationArchiving(); cRLArchiveDuration = builder.getRevocationArchiveDuration(); revocationArchiveJDBCURL_ = builder.getRevocationArchiveJDBCURL(); revocationArchiveJDBCDriverClass_ = builder.getRevocationArchiveJDBCDriverClass(); //TODO!!!! certStoreLocation_ = builder.getCertStoreLocation(); createTransformsInfoProfiles = builder.buildCreateTransformsInfoProfiles(); createSignatureEnvironmentProfiles = builder.buildCreateSignatureEnvironmentProfiles(); verifyTransformsInfoProfiles = builder.buildVerifyTransformsInfoProfiles(); supplementProfiles = builder.buildSupplementProfiles(); warnings = new ArrayList(builder.getWarnings()); permitFileURIs = builder.getPermitFileURIs(); crlRetentionIntervals = builder.getCrlRetentionIntervals(); allowExternalUris_= builder.allowExternalUris(); if (allowExternalUris_) { blackListedUris_ = builder.buildPermitExternalUris(); whiteListedUris_ = null; } else { info("config.35", null); blackListedUris_ = null; whiteListedUris_ = builder.buildForbidExternalUris(); } // Set set = crlRetentionIntervals.entrySet(); // Iterator i = set.iterator(); // while(i.hasNext()){ // Map.Entry me = (Map.Entry)i.next(); // System.out.println("Key: " + me.getKey() + " - Value: " + me.getValue() ); // } } catch (Throwable t) { throw new ConfigurationException("config.11", null, t); } finally { try { if (stream != null) { stream.close(); } } catch (IOException e) { // don't complain about this } } } // private boolean checkTSLenableTrustprofilesExist()throws ConfigurationException { // boolean bTSLEnabledTPExist = false; // Iterator it = trustProfiles.entrySet().iterator(); // while (it.hasNext()) { // Map.Entry pairs = (Map.Entry)it.next(); // TrustProfile tp = (TrustProfile) pairs.getValue(); // if (tp.isTSLEnabled()) // bTSLEnabledTPExist = bTSLEnabledTPExist || true; // } // // return bTSLEnabledTPExist; // // } private void checkTSLConfiguration() throws ConfigurationException { boolean bTSLEnabledTPExist = false; Iterator it = trustProfiles.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry)it.next(); TrustProfile tp = (TrustProfile) pairs.getValue(); if (tp.isTSLEnabled()) bTSLEnabledTPExist = bTSLEnabledTPExist || true; } if (!bTSLEnabledTPExist) { // if no trustprofile has TSL support enabled, delete TSL configuration tslconfiguration_ = null; return; } if (bTSLEnabledTPExist && (tslconfiguration_ == null)) { error("config.40", null); throw new ConfigurationException("config.40", null); } File workingDir = new File(tslconfiguration_.getWorkingDirectory()); File eu_trust = new File(workingDir.getAbsolutePath() + "/trust/eu"); if (!eu_trust.exists()) { error("config.51", new Object[] {"Verzeichnis \"trust/eu\" existiert nicht"}); throw new ConfigurationException("config.51", new Object[] {"Verzeichnis \"trust/eu\" existiert nicht"}); } else { File[] eutrustFiles = eu_trust.listFiles(); if (eutrustFiles == null) { error("config.51", new Object[] {"Verzeichnis \"trust/eu\" ist leer"}); throw new ConfigurationException("config.51", new Object[] {"Verzeichnis \"trust/eu\" ist leer"}); } else { if (eutrustFiles.length == 0) { error("config.51", new Object[] {"Verzeichnis \"trust/eu\" ist leer"}); throw new ConfigurationException("config.51", new Object[] {"Verzeichnis \"trust/eu\" ist leer"}); } } } File hashcache = new File(tslconfiguration_.getWorkingDirectory(), "hashcache"); if (!hashcache.exists()) { hashcache.mkdir(); } if (!hashcache.isDirectory()) { error("config.38", new Object[] { hashcache.getAbsolutePath() }); return; } // System.setProperty("iaik.xml.crypto.tsl.BinaryHashCache.DIR", hashcache.getAbsolutePath()); // String hashcachedir = System.getProperty("iaik.xml.crypto.tsl.BinaryHashCache.DIR"); // System.out.println("Hashcache: " + hashcachedir); Logger.debug("TSL Konfiguration - Hashcache: " + hashcache.getAbsolutePath()); } /** * Returns the warnings encountered during building the configuration. * * @return A List of Strings, containing the * warning messages. */ public List getWarnings() { return warnings; } /** * Return the name of the digest algorithm used during signature creation. * * @return The digest method algorithm name, or an empty String, * if none has been configured. */ public String getDigestMethodAlgorithmName() { return digestMethodAlgorithmName; } /** * Return the XAdES version used for signature creation. * * @return The XAdES version used for signature creation, or an empty String, * if none has been configured. */ public String getXAdESVersion() { return xadesVersion; } public String getPDFASConfiguration() { return pdfAsConfiguration; } public int getConnectionTimeout() { return this.connectionTimeout; } public int getReadTimeout() { return this.readTimeout; } public boolean getAdesFormResults() { return this.adesFormResults; } public boolean getAllowExternalUris() { return this.allowExternalUris_; } public List getBlackListedUris() { return this.blackListedUris_; } public List getWhiteListedUris() { return this.whiteListedUris_; } /** * Return the name of the canonicalization algorithm used during signature * creation. * * @return The canonicalization algorithm name, or an empty * String if none has been configured. */ public String getCanonicalizationAlgorithmName() { return canonicalizationAlgorithmName; } /** * Return the configured hardware crypto modules. * * @return A List of HardwareCryptoModule objects * containing the hardware crypto module configurations. */ public List getHardwareCryptoModules() { return hardwareCryptoModules; } /** * Return the hardware key modules configuration. * * @return A List of HardwareKeyModule objects * containing the configuration of the hardware key modules. */ public List getHardwareKeyModules() { return hardwareKeyModules; } /** * Return the software key module configuration. * * @return A List of SoftwareKeyModule objects * containing the configuration of the software key modules. */ public List getSoftwareKeyModules() { return softwareKeyModules; } /** * Return the key group mapping. * * @return A mapping from key group ID (a String) to * KeyGroup mapping. */ public Map getKeyGroups() { return keyGroups; } public KeyGroup getKeyGroup(String keyGroupId) { if (MiscUtil.isNotEmpty(keyGroupId)) return (KeyGroup) keyGroups.get(keyGroupId.trim().toLowerCase()); else return null; } /** * Return the set of KeyGroupEntrys of a given key group, which a * client (identified by an issuer/serial pair) may access. * * @param issuer The issuer of the client certificate. * @param serial The serial number of the client certificate. * @param keyGroupId The ID of the key group. * @return A Set of all the KeyGroupEntrys in the * given key group, if the user may access them. Returns null, if * the user may not access the given key group or if the key group does not * exist. */ public Set getKeyGroupEntries( Principal issuer, BigInteger serial, String keyGroupId) { IssuerAndSerial issuerAndSerial; Map mapping; if (issuer == null && serial == null) { issuerAndSerial = ANONYMOUS_ISSUER_SERIAL; } else { issuerAndSerial = new IssuerAndSerial(issuer, serial); } // System.out.println("Issuer: " + issuer); // System.out.println("serial: " + serial); // // Iterator entries = keyGroupMappings.entrySet().iterator(); // while (entries.hasNext()) { // Entry thisEntry = (Entry) entries.next(); // System.out.println("Entry: " + thisEntry.getKey()); // System.out.println("Value: " + thisEntry.getValue()); // } mapping = (Map) keyGroupMappings.get(issuerAndSerial); if (mapping != null) { KeyGroup keyGroup = (KeyGroup) mapping.get(keyGroupId); if (keyGroup != null) { return keyGroup.getKeyGroupEntries(); } } // If no key group is available for a client identified by a certificate, // try to find a key group in the anonymous key group mapping if (issuer != null || serial != null) { mapping = (Map) keyGroupMappings.get(ANONYMOUS_ISSUER_SERIAL); if (mapping != null) { KeyGroup keyGroup = (KeyGroup) mapping.get(keyGroupId); if (keyGroup != null) return keyGroup.getKeyGroupEntries(); } } return null; } /** * Return the chaining mode for a given trust anchor. * * @param trustAnchor The trust anchor for which the chaining mode should be * returned. * @return The chaining mode for the given trust anchor. If the trust anchor * has not been configured separately, the system default will be returned. */ public String getChainingMode(X509Certificate trustAnchor) { Principal issuer = trustAnchor.getIssuerDN(); BigInteger serial = trustAnchor.getSerialNumber(); IssuerAndSerial issuerAndSerial = new IssuerAndSerial(issuer, serial); String mode = (String) chainingModes.get(issuerAndSerial); return mode != null ? mode : defaultChainingMode; } /** * Return the distribution points for a given CA. * * @param cert The certificate for which the distribution points should be * looked up. The issuer information is used to perform the lookup. * * @return A Set of DistributionPoint objects. The * set will be empty, if no distribution points have been configured * for this certificate. */ public Set getDistributionPoints(X509Certificate cert) { try { RFC2253NameParser nameParser = new RFC2253NameParser(cert.getIssuerDN().toString()); String caIssuerDN = nameParser.parse().getName(); Set dps = (Set) distributionPoints.get(caIssuerDN); if (dps == null) { return Collections.EMPTY_SET; } return dps; } catch (RFC2253NameParserException e) { return Collections.EMPTY_SET; } } /** * Return the CRL archive duration. * * @return The duration of how long to keep CRL archive entries (measured in * days). */ public int getCRLArchiveDuration() { return cRLArchiveDuration; } /** * Returns whether revocation information should be archived. * * @return whether revocation information should be archived. */ public boolean getEnableRevocationArchiving() { return enableRevocationArchiving_; } /** * Returns the location of the certificate store. * * @return the location of the certificate store. */ public String getCertStoreLocation() { return certStoreLocation_; } /** * Return a CreateTransformsInfoProfile with the given ID. * * @param id The CreateTransformsInfoProfile ID. * @return The CreateTransformsInfoProfile with the given * ID or null, if none exists. */ public Element getCreateTransformsInfoProfile(String id) { return (Element) createTransformsInfoProfiles.get(id); } /** * Return a CreateSignatureEnvironmentProfile with the given ID. * * @param id The CreateSignatureEnvironmentProfile ID. * @return The CreateSignatureEnvironmentProfile with the given * ID or null, if none exists. */ public Element getCreateSignatureEnvironmentProfile(String id) { return (Element) createSignatureEnvironmentProfiles.get(id); } /** * Return a VerifyTransformsInfoProfile with the given ID. * * @param id The VerifyTransformsInfoProfile ID. * @return The VerifyTransformsInfoProfile with the given ID or * null, if none exists. */ public Element getVerifyTransformsInfoProfile(String id) { return (Element) verifyTransformsInfoProfiles.get(id); } /** * Return a SupplementProfile with the given ID. * * @param id The SupplementProfile ID. * @return The SupplementProfile with the given ID or * null, if none exists. */ public Element getSupplementProfile(String id) { return (Element) supplementProfiles.get(id); } /** * Return a TrustProfile with the given ID. * * @param id The TrustProfile ID. * @return The TrustProfile with the given ID or * null, if none exists. */ public TrustProfile getTrustProfile(String id) { if (MiscUtil.isNotEmpty(id)) { id = id.trim().toLowerCase(); return (TrustProfile) trustProfiles.get(id); } return null; } /** * Returns a map of TrustProfiles * @return */ public Map getTrustProfiles() { return trustProfiles; } /** * Log a warning. * * @param messageId The message ID. * @param parameters Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private static void info(String messageId, Object[] parameters) { MessageProvider msg = MessageProvider.getInstance(); Logger.info(new LogMsg(msg.getMessage(messageId, parameters))); } /** * Log a debug message. * * @param messageId The message ID. * @param parameters Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private static void debug(String message) { Logger.debug(message); } /** * Log a warning. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void warn(String messageId, Object[] args) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.warn(new LogMsg(txt)); warnings.add(txt); } /** * Log an error. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void error(String messageId, Object[] args) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.warn(new LogMsg(txt)); // warnings.add(txt); } /** * Returns the JDBC URL for the revocation archive database. * * @return the JDBC URL for the revocation archive database. */ public String getRevocationArchiveJDBCURL() { return revocationArchiveJDBCURL_; } /** * Returns the JDBC driver class name for the revocation archive database. * * @return the JDBC driver class name for the revocation archive database. */ public String getRevocationArchiveJDBCDriverClass() { return revocationArchiveJDBCDriverClass_; } /** * Returns whether revocation checking should be done. * * @return whether revocation checking should be done. */ public boolean getEnableRevocationChecking() { return enableRevocationChecking_; } /** * Returns the maximum age of a revocation information for considering it * still as valid. * * @return the maximum age of a revocation information for considering it * still as valid. */ public long getMaxRevocationAge() { return maxRevocationAge_; } /** * Returns the service order for revocation checking. * * @return the service order for revocation checking. Valid array entries are * {@link RevocationSourceTypes#OCSP} and {@link RevocationSourceTypes#CRL}. */ public String[] getServiceOrder() { return serviceOrder_; } /** * Returns whether certificates found during certificate path construction * should be added to the certificate store. * * @return whether certificates found during certificate path construction * should be added to the certificate store. */ public boolean getAutoAddCertificates() { return autoAddCertificates_; } /** * Returns whether the certificate extension Authority Info Access should * be used during certificate path construction. * * @return whether the certificate extension Authority Info Access should * be used during certificate path construction. */ public boolean getUseAuthorityInfoAccess() { return useAuthorityInfoAccess_; } /** * Returns whether the file URIs are permitted or not * @return whether the file URIs are permitted or not */ public boolean getPermitFileURIs() { return permitFileURIs; } /** * Returns the map of retention intervals * @return The map of retention intervals */ public Map getCrlRetentionIntervals() { return crlRetentionIntervals; } /** * Returns the global TSL configuration * @return The global TSL configuration */ public TSLConfiguration getTSLConfiguration() { return tslconfiguration_; } }