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.pki.revocation.RevocationSourceTypes; 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"; /** * 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 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_; /** * 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_; /** * 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); 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); defaultChainingMode = builder.getDefaultChainingMode(); chainingModes = builder.buildChainingModes(); useAuthorityInfoAccess_ = builder.getUseAuthorityInfoAccess(); autoAddCertificates_ = builder.getAutoAddCertificates(); trustProfiles = builder.buildTrustProfiles(); distributionPoints = builder.buildDistributionPoints(); enableRevocationChecking_ = builder.getEnableRevocationChecking(); maxRevocationAge_ = builder.getMaxRevocationAge(); serviceOrder_ = builder.getServiceOrder(); enableRevocationArchiving_ = builder.getEnableRevocationArchiving(); cRLArchiveDuration = builder.getRevocationArchiveDuration(); revocationArchiveJDBCURL_ = builder.getRevocationArchiveJDBCURL(); revocationArchiveJDBCDriverClass_ = builder.getRevocationArchiveJDBCDriverClass(); certStoreLocation_ = builder.getCertStoreLocation(); createTransformsInfoProfiles = builder.buildCreateTransformsInfoProfiles(); createSignatureEnvironmentProfiles = builder.buildCreateSignatureEnvironmentProfiles(); verifyTransformsInfoProfiles = builder.buildVerifyTransformsInfoProfiles(); supplementProfiles = builder.buildSupplementProfiles(); warnings = new ArrayList(builder.getWarnings()); } 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; } /** * 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(); } } // 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) { 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); } /** * 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_; } }