package at.gv.egovernment.moa.spss.server.config; 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.List; import java.util.Map; import java.util.Set; import org.w3c.dom.Element; import iaik.asn1.structures.Name; import iaik.utils.RFC2253NameParser; import iaik.utils.RFC2253NameParserException; import at.gv.egovernment.moa.logging.LogMsg; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.DOMUtils; import at.gv.egovernment.moa.spss.util.MessageProvider; /** * 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"; /** * The name of the generic configuration property giving the root directory of * a directory based cert store. */ public static final String DIRECTORY_CERTSTORE_PARAMETER_PROPERTY = "DirectoryCertStoreParameters.RootDir"; /** The name of the generic configuration property which determines if * certificates should be added to the cert store automatically. */ public static final String AUTO_ADD_CERTIFICATES_PROPERTY = "autoAddCertificates"; /** The name of the generic configuration property whether the authority * info access should be used. */ public static final String USE_AUTHORITY_INFO_ACCESS_PROPERTY = "useAuthorityInfoAccess"; /** The name of the generic configuration property determining the maximum * age of CRL entries. */ public static final String MAX_REVOCATION_AGE_PROPERTY = "maxRevocationAge"; /** * The name of the generic configuration property giving the database URL of * the CRL archive. */ public static final String DATABASE_ARCHIVE_PARAMETER_PROPERTY = "DataBaseArchiveParameter.JDBCUrl"; /** The name of the generic configuration property determining whether * to check the revocation status of signer certificates. */ public static final String REVOCATION_CHECKING_PROPERTY = "checkRevocation"; /** The name of the generic configuration property determining whether to * archive revocation information. */ public static final String ARCHIVE_REVOCATION_INFO_PROPERTY = "archiveRevocationInfo"; /** The name of the generic configuration property used for setting the * signing time to a predefined value. (Use for testing purposes only). */ public static final String TEST_SIGNING_TIME_PROPERTY = "test.SigningTime"; /** * 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; /** * A Map which contains generic configuration information. Maps a * configuration name (a String) to a configuration value (also a * String). */ private Map genericConfiguration; /** * 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 crlDistributionPoints; /** The CRL archive duration. */ private int cRLArchiveDuration; /** * 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; /** * 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); digestMethodAlgorithmName = builder.getDigestMethodAlgorithmName(); canonicalizationAlgorithmName = builder.getCanonicalizationAlgorithmName(); hardwareCryptoModules = builder.buildHardwareCryptoModules(); hardwareKeyModules = builder.buildHardwareKeyModules(Collections.EMPTY_LIST); softwareKeyModules = builder.buildSoftwareKeyModules(hardwareKeyModules, configRoot); allKeyModules = new ArrayList(hardwareKeyModules); allKeyModules.addAll(softwareKeyModules); keyGroups = builder.buildKeyGroups(allKeyModules); keyGroupMappings = builder.buildKeyGroupMappings(keyGroups, ANONYMOUS_ISSUER_SERIAL); defaultChainingMode = builder.getDefaultChainingMode(); chainingModes = builder.buildChainingModes(); crlDistributionPoints = builder.buildCRLDistributionPoints(); cRLArchiveDuration = builder.getCRLArchiveDuration(); genericConfiguration = builder.buildGenericConfiguration(); absolutizeCertStoreRoot(configRoot); createTransformsInfoProfiles = builder.buildCreateTransformsInfoProfiles(configRoot); createSignatureEnvironmentProfiles = builder.buildCreateSignatureEnvironmentProfiles(configRoot); verifyTransformsInfoProfiles = builder.buildVerifyTransformsInfoProfiles(configRoot); supplementProfiles = builder.buildSupplementProfiles(configRoot); trustProfiles = builder.buildTrustProfiles(configRoot); warnings = new ArrayList(builder.getWarnings()); checkConsistency(); } 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 } } } /** * Returns the warnings encountered during building the configuration. * * @return A List of Strings, containing the * warning messages. */ public List getWarnings() { return warnings; } /** * Make the DIRECTORY_CERTSTORE_PARAMETER_PROPERTY generic * configuration value an absolute file name. * * @param configRoot The root directory of the main configuration file. */ private void absolutizeCertStoreRoot(File configRoot) { String certStoreRoot = getGenericConfiguration(DIRECTORY_CERTSTORE_PARAMETER_PROPERTY); if (certStoreRoot != null) { if (!new File(certStoreRoot).isAbsolute()) { // make the cert store absolute File absCertStore = new File(configRoot, certStoreRoot); setGenericConfiguration( DIRECTORY_CERTSTORE_PARAMETER_PROPERTY, absCertStore.getAbsolutePath()); } } else { // no value given: set it to a reasonable (absolute) default File absCertStore = new File(configRoot, "certstore"); setGenericConfiguration( DIRECTORY_CERTSTORE_PARAMETER_PROPERTY, absCertStore.getAbsolutePath()); } } /** * Do some additional consistency checks on the configuration. */ private void checkConsistency() { // check for valid DirectoryCertStoreParameters.RootDir String certStoreRoot = getGenericConfiguration(DIRECTORY_CERTSTORE_PARAMETER_PROPERTY); if (certStoreRoot != null) { File certStore = new File(certStoreRoot); if (!certStore.exists() && !certStore.isDirectory()) { boolean created = false; try { created = certStore.mkdirs(); } finally { if (!created) { warn( "config.30", new Object[] { DIRECTORY_CERTSTORE_PARAMETER_PROPERTY }); } } } } } /** * 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 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; } /** * 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); } mapping = (Map) keyGroupMappings.get(issuerAndSerial); 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 CRL distribution points for a given CA. * * @param cert The certificate for which the CRL 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 getCRLDP(X509Certificate cert) { try { RFC2253NameParser nameParser = new RFC2253NameParser(cert.getIssuerDN().toString()); String caIssuerDN = nameParser.parse().getName(); Set dps = (Set) crlDistributionPoints.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; } /** * Sets a generic configuration value. * * Existing values are overridden. * * @param name The name of the generic configuration. * @param value The new value of the generic configuration. */ private void setGenericConfiguration(String name, String value) { genericConfiguration.put(name, value); } /** * Return the value of a generic configuration. * * @param name The name of the generic configuration. * @return The value of the generic configuration with the given name, or * null, if none can be found. */ public String getGenericConfiguration(String name) { return (String) genericConfiguration.get(name); } /** * Return the value of a generic configuration, or a given default value. * * @param name The name of the generic configuration. * @param defaultValue A default value to be returned in case that the generic * configuration with the given name does not exist. * @return The value of the generic configuration with the given name, or the * defaultValue, if none can be found. */ public String getGenericConfiguration(String name, String defaultValue) { String value = (String) genericConfiguration.get(name); return value != null ? value : defaultValue; } /** * 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) { return (TrustProfile) trustProfiles.get(id); } /** * 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 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); } }