diff options
Diffstat (limited to 'connector')
31 files changed, 749 insertions, 523 deletions
diff --git a/connector/pom.xml b/connector/pom.xml index a461ab79..9f1e6c50 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -9,19 +9,23 @@ <groupId>at.gv.egiz.eidas.ms_specific</groupId> <artifactId>ms_specific_connector</artifactId> - <packaging>war</packaging> <version>${egiz.eidas.version}</version> + <packaging>war</packaging> <name>Connector Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> - <!-- Web application --> + <!-- Web application --> - <dependency> + <dependency> <groupId>at.gv.egiz.components</groupId> <artifactId>egiz-spring-api</artifactId> </dependency> <dependency> + <groupId>at.gv.egiz.components</groupId> + <artifactId>eventlog-slf4j</artifactId> + </dependency> + <dependency> <groupId>at.gv.egiz.eaaf</groupId> <artifactId>eaaf-core</artifactId> </dependency> @@ -33,8 +37,16 @@ <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </exclusion> - </exclusions> - </dependency> + </exclusions> + </dependency> + <dependency> + <groupId>at.gv.egiz.eidas.ms_specific</groupId> + <artifactId>connector_lib</artifactId> + </dependency> + <dependency> + <groupId>at.gv.egiz.eidas.ms_specific.modules</groupId> + <artifactId>authmodule-eIDAS-v2</artifactId> + </dependency> <!-- Third party libs --> <dependency> @@ -49,7 +61,10 @@ <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> - + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> @@ -63,6 +78,12 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> <build> <finalName>ms_connector</finalName> @@ -82,7 +103,6 @@ <artifactId>maven-surefire-plugin</artifactId> <configuration> <threadCount>1</threadCount> - <argLine>--add-modules java.xml.bind</argLine> </configuration> <dependencies> <dependency> diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSSpecificeIDASNodeSpringResourceProvider.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSSpecificeIDASNodeSpringResourceProvider.java index f64b6073..6dacc33b 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSSpecificeIDASNodeSpringResourceProvider.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSSpecificeIDASNodeSpringResourceProvider.java @@ -12,7 +12,8 @@ public class MSSpecificeIDASNodeSpringResourceProvider implements SpringResource @Override public Resource[] getResourcesToLoad() { ClassPathResource mseIDASNode = new ClassPathResource("/specific_eIDAS_connector.beans.xml", MSSpecificeIDASNodeSpringResourceProvider.class); - return new Resource[] {mseIDASNode}; + ClassPathResource mseIDASNodeStorage = new ClassPathResource("/specific_eIDAS_connector.storage.beans.xml", MSSpecificeIDASNodeSpringResourceProvider.class); + return new Resource[] {mseIDASNode, mseIDASNodeStorage}; } @Override diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java deleted file mode 100644 index 94c77297..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector; - -import at.gv.egiz.eaaf.core.api.data.EAAFConfigConstants; -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; - -public class MSeIDASNodeConstants { - //configuration properties - public static final String PROP_CONFIG_APPLICATION_PREFIX = "eidas.ms."; - public static final String PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX = "context.url.prefix"; - - private static final String PROP_CONFIG_PVP2_PREFIX = "pvp2."; - public static final String PROP_CONFIG_PVP2_KEYSTORE_PATH = PROP_CONFIG_PVP2_PREFIX + "keystore.path"; - public static final String PROP_CONFIG_PVP2_KEYSTORE_PASSWORD = PROP_CONFIG_PVP2_PREFIX + "keystore.password"; - public static final String PROP_CONFIG_PVP2_KEY_METADATA_ALIAS = PROP_CONFIG_PVP2_PREFIX + "key.metadata.alias"; - public static final String PROP_CONFIG_PVP2_KEY_METADATA_PASSWORD = PROP_CONFIG_PVP2_PREFIX + "key.metadata.password"; - public static final String PROP_CONFIG_PVP2_KEY_SIGNING_ALIAS = PROP_CONFIG_PVP2_PREFIX + "key.signing.alias"; - public static final String PROP_CONFIG_PVP2_KEY_SIGNING_PASSWORD = PROP_CONFIG_PVP2_PREFIX + "key.signing.password"; - public static final String PROP_CONFIG_PVP2_METADATA_VALIDITY = PROP_CONFIG_PVP2_PREFIX + "metadata.validity"; - - public static final String PROP_CONFIG_SP_LIST_PREFIX = "sp."; - public static final String PROP_CONFIG_SP_UNIQUEIDENTIFIER = EAAFConfigConstants.SERVICE_UNIQUEIDENTIFIER; - public static final String PROP_CONFIG_SP_FRIENDLYNAME = "friendlyName"; - public static final String PROP_CONFIG_SP_PVP2_METADATA_URL = "pvp2.metadata.url"; - public static final String PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE = "pvp2.metadata.truststore"; - public static final String PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE_PASSWORD = "pvp2.metadata.truststore.password"; - public static final String PROP_CONFIG_SP_POLICY_ALLOWED_TARGETS = "policy.allowed.requested.targets"; - public static final String PROP_CONFIG_SP_POLICY_BASEIDTRANSFER_RESTRICTION = "policy.hasBaseIdTransferRestriction"; - - public static final String PROP_CONFIG_PVP_SCHEME_VALIDATION = "configuration.pvp.scheme.validation"; - public static final String PROP_CONFIG_PVP_ENABLE_ENTITYCATEGORIES = "configuration.pvp.enable.entitycategories"; - - //default values - public static final String POLICY_DEFAULT_ALLOWED_TARGETS = - EAAFConstants.URN_PREFIX_CDID.replaceAll("\\.", "\\\\.").replaceAll("\\+", "\\\\+") + ".*"; - public static final int METADATA_SOCKED_TIMEOUT = 20 * 1000; //20 seconds metadata socked timeout - public static final int DEFAULT_PVP_METADATA_VALIDITY = 24; //24 hours - - //application end-points - public static final String ENDPOINT_PVP_METADATA = "/pvp/metadata"; - public static final String ENDPOINT_PVP_POST = "/pvp/post"; - public static final String ENDPOINT_PVP_REDIRECT = "/pvp/redirect"; - - public static final String ENDPOINT_COUNTRYSELECTION = "/myHomeCountry"; - - //paths and templates - public static final String CLASSPATH_TEMPLATE_DIR = "/templates/"; - - public static final String TEMPLATE_HTML_ERROR = "error.html"; - public static final String TEMPLATE_HTML_PVP_POSTBINDING = "pvp2_post_binding.html"; - public static final String TEMPLATE_HTML_COUNTRYSELECTION = "countrySelection.html"; - - //execution context and generic data - public static final String REQ_PARAM_SELECTED_COUNTRY = "selectedCountry"; - public static final String DATA_REQUESTERID = "req_requesterId"; - public static final String DATA_PROVIDERNAME = "req_providerName"; - public static final String DATA_REQUESTED_LOA_LIST = "req_requestedLoA"; - public static final String DATA_REQUESTED_LOA_COMPERISON = "req_requestedLoAComperision"; - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/SpringInitializer.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/SpringInitializer.java index d5c2632c..0e115ad0 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/SpringInitializer.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/SpringInitializer.java @@ -25,6 +25,9 @@ import org.springframework.web.context.support.ServletContextResource; import org.springframework.web.servlet.DispatcherServlet; import at.gv.egiz.components.spring.api.SpringLoader; +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; +import at.gv.egiz.eaaf.core.impl.utils.Random; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap; /** @@ -134,11 +137,14 @@ public class SpringInitializer implements WebApplicationInitializer { log.info("=============== Register RequestContextListener! ==============="); servletContext.addListener(new RequestContextListener()); - //TODO: integrate message provider!!!! - //log.info(MOAIDMessageProvider.getInstance().getMessage("init.00", null)); + //initialize status messenger + LogMessageProviderFactory.setStatusMessager(rootContext.getBean(IStatusMessenger.class)); log.info("Bootstrap openSAML .... "); EAAFDefaultSAML2Bootstrap.bootstrap(); + + log.info("Seed random number generator ... "); + Random.seedRandom(); log.info("Initialization of MS-specific eIDAS-connector finished."); diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/AuthenticationDataBuilder.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/AuthenticationDataBuilder.java index 775e36f2..34f964fb 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/AuthenticationDataBuilder.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/AuthenticationDataBuilder.java @@ -2,6 +2,8 @@ *******************************************************************************/ package at.gv.egiz.eidas.specific.connector.builder; +import java.util.Date; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -20,6 +22,7 @@ import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; @Service("AuthenticationDataBuilder") public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder { @@ -28,27 +31,37 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder @Override public IAuthData buildAuthenticationData(IRequest pendingReq) throws EAAFAuthenticationException { - IAuthProcessDataContainer authProcessData = new AuthProcessDataWrapper(pendingReq.genericFullDataStorage()); + IAuthProcessDataContainer authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); AuthenticationData authData = new AuthenticationData(); try { generateBasicAuthData(authData, pendingReq, authProcessData); + //set specific informations + authData.setSsoSessionValidTo(new Date(new Date().getTime() + + MSeIDASNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); + } catch (EAAFBuilderException | EAAFParserException | EAAFConfigurationException | XPathException | DOMException e) { log.warn("Can not build authentication data from auth. process information"); - throw new EAAFAuthenticationException("TODO", new Object[]{}, - "Can not build authentication data from auth. process information", e); + throw new EAAFAuthenticationException("builder.11", new Object[]{e.getMessage()}, e); } + return authData; - - - return null; } @Override + protected Pair<String, String> buildOAspecificbPK(IRequest pendingReq, AuthenticationData authData) throws EAAFBuilderException { + //TODO: check if bPK already exists + + + return super.buildOAspecificbPK(pendingReq, authData); + + } + + @Override protected Pair<String, String> getEncryptedbPKFromPVPAttribute(IAuthProcessDataContainer arg0, AuthenticationData arg1, ISPConfiguration arg2) throws EAAFBuilderException { return null; diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/PVPSubjectNameGenerator.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/PVPSubjectNameGenerator.java index d640539a..1435dd96 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/PVPSubjectNameGenerator.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/builder/PVPSubjectNameGenerator.java @@ -12,7 +12,6 @@ public class PVPSubjectNameGenerator implements ISubjectNameIdGenerator { @Override public Pair<String, String> generateSubjectNameId(IAuthData authData, ISPConfiguration spConfig) throws PVP2Exception { - //TODO: maybe update return Pair.newInstance(authData.getBPK(), authData.getBPKType()); } diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/BasicConfigurationProvider.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/BasicConfigurationProvider.java deleted file mode 100644 index b898dfef..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/BasicConfigurationProvider.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector.config; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; -import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.impl.idp.conf.AbstractConfigurationImpl; -import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; -import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; - -@Service("BasicMSSpecificNodeConfig") -public class BasicConfigurationProvider extends AbstractConfigurationImpl{ - private static final Logger log = LoggerFactory.getLogger(BasicConfigurationProvider.class); - - private Map<String, ISPConfiguration> spConfigCache = new HashMap<String, ISPConfiguration>(); - - public BasicConfigurationProvider(String configPath) throws EAAFConfigurationException { - super(configPath); - - } - - @Override - public ISPConfiguration getServiceProviderConfiguration(String entityId) throws EAAFConfigurationException { - if (!spConfigCache.containsKey(entityId)) { - log.debug("SP: " + entityId + " is NOT cached. Starting load operation ... "); - Map<String, String> allSPs = getBasicMOAIDConfigurationWithPrefix(MSeIDASNodeConstants.PROP_CONFIG_SP_LIST_PREFIX); - for (String key : allSPs.keySet()) { - if (key.endsWith(MSeIDASNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER) && - allSPs.get(key).equals(entityId)) { - String listId = KeyValueUtils.getParentKey(key); - log.trace("Find SP configuration with list-Id: " + listId + ". Extracting configuration elements ... "); - Map<String, String> spConfig = KeyValueUtils.getSubSetWithPrefix(allSPs, listId + KeyValueUtils.KEY_DELIMITER); - spConfigCache.put(entityId, - new ServiceProviderConfiguration(spConfig, this)); - break; - } - } - - if (spConfigCache.containsKey(entityId)) - log.info("SP: " + entityId + " is loaded. Continuing auth. process ... "); - else { - log.warn("SP: " + entityId + " is NOT found in configuration. Stopping auth. process ... "); - return null; - - } - - } else - log.trace("SP: " + entityId + " is already cached. Use configuration from there ... "); - - - return spConfigCache.get(entityId); - } - - @Override - public <T> T getServiceProviderConfiguration(String entityId, Class<T> decorator) throws EAAFConfigurationException { - ISPConfiguration spConfig = getServiceProviderConfiguration(entityId); - if (spConfig != null && decorator != null) { - if (decorator.isInstance(spConfig)) - return (T)spConfig; - else - log.error("SPConfig: " + spConfig.getClass().getName() + " is NOT instance of: " + decorator.getName()); - - } - - return null; - - } - - @Override - public String validateIDPURL(URL url) throws EAAFException { - log.trace("Validate requested URL: " + url); - String urlPrefixFromConfig = getBasicConfiguration(MSeIDASNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX); - if (StringUtils.isEmpty(urlPrefixFromConfig)) { - log.warn("Application config containts NO URL prefix"); - throw new EAAFConfigurationException("Application config containts NO URL prefix"); - - } - - //remove last slash - if (urlPrefixFromConfig.endsWith("/")) - urlPrefixFromConfig = urlPrefixFromConfig.substring(0, urlPrefixFromConfig.length()-1); - - if (url != null && url.toExternalForm().startsWith(urlPrefixFromConfig)) - return urlPrefixFromConfig; - - - log.info("URL: " + url + " does NOT match to allowed application prefix: " + urlPrefixFromConfig); - return null; - } - - @Override - public String getApplicationSpecificKeyPrefix() { - return MSeIDASNodeConstants.PROP_CONFIG_APPLICATION_PREFIX; - - } - - @Override - protected String getBackupConfigPath() { - return null; - - } - - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/PVPEndPointConfiguration.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/PVPEndPointConfiguration.java index 21e46e10..3a7bf379 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/PVPEndPointConfiguration.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/PVPEndPointConfiguration.java @@ -49,13 +49,11 @@ public class PVPEndPointConfiguration implements IPVP2BasicConfiguration { @Override public List<ContactPerson> getIDPContacts() throws EAAFException { - // TODO Auto-generated method stub return null; } @Override public Organization getIDPOrganisation() throws EAAFException { - // TODO Auto-generated method stub return null; } diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/ServiceProviderConfiguration.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/ServiceProviderConfiguration.java deleted file mode 100644 index 3d8a3bdd..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/config/ServiceProviderConfiguration.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector.config; - -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.impl.idp.conf.SPConfigurationImpl; -import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; - -public class ServiceProviderConfiguration extends SPConfigurationImpl { - private static final long serialVersionUID = 1L; - private static final Logger log = LoggerFactory.getLogger(ServiceProviderConfiguration.class); - - private String minimumLoA = EAAFConstants.EIDAS_QAA_HIGH; - private String bPKTargetIdentifier; - - public ServiceProviderConfiguration(Map<String, String> spConfig, IConfiguration authConfig) { - super(spConfig, authConfig); - - } - - @Override - public boolean hasBaseIdInternalProcessingRestriction() { - return false; - - } - - @Override - public boolean hasBaseIdTransferRestriction() { - return isConfigurationValue( - MSeIDASNodeConstants.PROP_CONFIG_SP_POLICY_BASEIDTRANSFER_RESTRICTION, - true); - - } - - @Override - public String getMinimumLevelOfAssurence() { - return minimumLoA; - - } - - - @Override - public String getAreaSpecificTargetIdentifier() { - return bPKTargetIdentifier; - } - - - @Override - public String getFriendlyName() { - return getConfigurationValue( - MSeIDASNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME, - "NO FRIENDLYNAME SET"); - - } - - /** - * Set the minimum level of eIDAS authentication for this SP - * <br> - * <b>Default:</b> http://eidas.europa.eu/LoA/high or - * - * @param minimumLoA eIDAS LoA URI - */ - - public void setMinimumLoA(String minimumLoA) { - this.minimumLoA = minimumLoA; - } - - - /** - * Set the bPK Target for this service provider - * - * @param bPKTargetIdentifier - * @throws EAAFException If the bPKTargetIdentifier is NOT ALLOWED for this service provider - */ - public void setbPKTargetIdentifier(String bPKTargetIdentifier) throws EAAFException { - String allowedTargetIdentifierRegExPattern = getConfigurationValue( - MSeIDASNodeConstants.PROP_CONFIG_SP_POLICY_ALLOWED_TARGETS, - MSeIDASNodeConstants.POLICY_DEFAULT_ALLOWED_TARGETS); - log.trace("Use bPK-target regex pattern: " + allowedTargetIdentifierRegExPattern); - - Pattern p = Pattern.compile(allowedTargetIdentifierRegExPattern); - Matcher m = p.matcher(bPKTargetIdentifier); - if (m.matches()) { - log.debug("Requested bPK-target: " + bPKTargetIdentifier + " matches regex pattern"); - this.bPKTargetIdentifier = bPKTargetIdentifier; - - } else { - log.warn("Requested bPK-target: " + bPKTargetIdentifier + " does NOT match regex pattern."); - throw new EAAFException("TODO", new Object[] {bPKTargetIdentifier}, - "Requested bPK-target: " + bPKTargetIdentifier + " does NOT match regex pattern."); - - } - - } - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/DefaultGUIBuilderImpl.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/DefaultGUIBuilderImpl.java deleted file mode 100644 index e423b09a..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/DefaultGUIBuilderImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector.gui; - -import java.io.InputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration; -import at.gv.egiz.eaaf.core.exceptions.GUIBuildException; -import at.gv.egiz.eaaf.core.impl.gui.AbstractGUIFormBuilderImpl; - -@Service("DefaultGUIBuilderImpl") -public class DefaultGUIBuilderImpl extends AbstractGUIFormBuilderImpl{ - private static final Logger log = LoggerFactory.getLogger(DefaultGUIBuilderImpl.class); - - private static final String CLASSPATH_HTMLTEMPLATES_DIR = "templates/"; - - public DefaultGUIBuilderImpl() throws GUIBuildException { - super(); - - } - - @Override - protected InputStream getInternalTemplate(IGUIBuilderConfiguration config) throws GUIBuildException { - String viewName = config.getViewName(); - log.debug("GUI template:" + viewName + " is not found in configuration directory. " - + " Load template from project library ... "); - String pathLocation = getInternalClasspathTemplateDir(config, CLASSPATH_HTMLTEMPLATES_DIR) + viewName; - try { - InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(pathLocation); - return is; - - } catch (Exception e1) { - log.error("GUI template:" + pathLocation + " is NOT loadable from classpath!", e1); - throw new GUIBuildException("GUI template:" + pathLocation + " is NOT loadable from classpath!", e1); - - } - - } - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/GUIBuilderConfigurationFactory.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/GUIBuilderConfigurationFactory.java deleted file mode 100644 index 8132c063..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/GUIBuilderConfigurationFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector.gui; - -import java.net.MalformedURLException; -import java.net.URI; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration; -import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfigurationFactory; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; - -@Service("GUIBuilderConfigurationFactory") -public class GUIBuilderConfigurationFactory implements IGUIBuilderConfigurationFactory { - @Autowired(required=true) private IConfiguration basicConfig; - - @Override - public IGUIBuilderConfiguration getDefaultErrorGUI(String authURL) { - return new StaticGuiBuilderConfiguration(basicConfig, authURL, MSeIDASNodeConstants.TEMPLATE_HTML_ERROR, null); - } - - @Override - public IGUIBuilderConfiguration getSPSpecificSAML2PostConfiguration(IRequest pendingReq, String viewName, URI configRootContextDir) - throws MalformedURLException { - return new StaticGuiBuilderConfiguration(basicConfig, pendingReq,MSeIDASNodeConstants.TEMPLATE_HTML_PVP_POSTBINDING , null); - } - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/StaticGuiBuilderConfiguration.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/StaticGuiBuilderConfiguration.java deleted file mode 100644 index 8dd3c580..00000000 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/gui/StaticGuiBuilderConfiguration.java +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eidas.specific.connector.gui; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.impl.gui.AbstractGUIFormBuilderConfiguration; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; -import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; - -public class StaticGuiBuilderConfiguration extends AbstractGUIFormBuilderConfiguration { - private static final Logger log = LoggerFactory.getLogger(StaticGuiBuilderConfiguration.class); - - private IRequest pendingReq = null; - private IConfiguration basicConfig = null; - - public StaticGuiBuilderConfiguration(IConfiguration basicConfig, String authURL, String viewName, String formSubmitEndpoint) { - super(authURL, viewName, formSubmitEndpoint); - this.basicConfig = basicConfig; - } - - public StaticGuiBuilderConfiguration(IConfiguration basicConfig, IRequest pendingReq, String viewName, String formSubmitEndpoint) { - super(pendingReq.getAuthURL(), viewName, formSubmitEndpoint); - this.pendingReq = pendingReq; - this.basicConfig = basicConfig; - - } - - @Override - public String getClasspathTemplateDir() { - return MSeIDASNodeConstants.CLASSPATH_TEMPLATE_DIR; - - } - - @Override - public String getDefaultContentType() { - return null; - - } - - @Override - public InputStream getTemplate(String viewName) { - String templateURL = MSeIDASNodeConstants.CLASSPATH_TEMPLATE_DIR + viewName; - try { - String absURL = FileUtils.makeAbsoluteURL(templateURL, this.basicConfig.getConfigurationRootDirectory()); - if (!absURL.startsWith("file:")) { - log.warn("Path to template looks like NOT absolut: " + absURL + ". Template loading FAILED"); - - } else { - log.debug("Load template URL for view: " + viewName + " from: " + absURL); - URI uri = new URL(absURL).toURI(); - return new FileInputStream(new File(uri)); - - } - - - } catch (MalformedURLException | URISyntaxException | FileNotFoundException e) { - log.warn("Can can build filesytem path to template: " + templateURL, e); - - } - - return null; - } - - @Override - protected Map<String, Object> getSpecificViewParameters() { - Map<String, Object> params = new HashMap<String, Object>(); - if (pendingReq != null) { - params.put(PARAM_PENDINGREQUESTID, StringEscapeUtils.escapeHtml(pendingReq.getPendingRequestId())); - - } - - return params; - } - -} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/RevisionLogger.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/RevisionLogger.java new file mode 100644 index 00000000..a4eaf9c4 --- /dev/null +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/RevisionLogger.java @@ -0,0 +1,66 @@ +package at.gv.egiz.eidas.specific.connector.logger; + +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.components.eventlog.api.Event; +import at.gv.egiz.components.eventlog.api.EventLogFactory; +import at.gv.egiz.components.eventlog.api.EventLoggingException; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; + +public class RevisionLogger extends EventLogFactory implements IRevisionLogger { + private static final Logger log = LoggerFactory.getLogger(RevisionLogger.class); + + @Override + public void logEvent(ISPConfiguration oaConfig, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message)); + + } + + @Override + public void logEvent(IRequest pendingRequest, int eventCode) { + logEvent(createNewEvent(new Date().getTime(), eventCode, + pendingRequest.getUniqueSessionIdentifier(), pendingRequest.getUniqueTransactionIdentifier())); + + } + + @Override + public void logEvent(IRequest pendingRequest, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message, + pendingRequest.getUniqueSessionIdentifier(), pendingRequest.getUniqueTransactionIdentifier())); + + } + + @Override + public void logEvent(int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message)); + + } + + @Override + public void logEvent(String sessionID, String transactionID, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message, sessionID, transactionID)); + + } + + @Override + public void logEvent(String sessionID, String transactionID, int eventCode) { + logEvent(createNewEvent(new Date().getTime(), eventCode, sessionID, transactionID)); + + } + + private void logEvent(Event event) { + try { + getEventLog().logEvent(event); + + } catch (EventLoggingException e) { + log.warn("Event logging FAILED! Reason: " + e.getMessage()); + + } + + } +} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/StatisticLogger.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/StatisticLogger.java new file mode 100644 index 00000000..ac4bca73 --- /dev/null +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/logger/StatisticLogger.java @@ -0,0 +1,116 @@ +package at.gv.egiz.eidas.specific.connector.logger; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; +import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; + +public class StatisticLogger implements IStatisticLogger { + + private static final Logger log = LoggerFactory.getLogger(StatisticLogger.class); + + private static final String DATEFORMATER = "yyyy.MM.dd-HH:mm:ss+z"; + private static final String STATUS_SUCCESS = "success"; + private static final String STATUS_ERROR = "error"; + + @Override + public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSSOSession) { + log.info(buildLogMessage( + protocolRequest.getUniqueTransactionIdentifier(), + protocolRequest.getSPEntityId(), + protocolRequest.getRawData(MSeIDASNodeConstants.DATA_REQUESTERID), + protocolRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), + authData.getCiticenCountryCode(), + STATUS_SUCCESS , + StringUtils.EMPTY, + StringUtils.EMPTY)); + + + } + + @Override + public void logErrorOperation(Throwable throwable) { + String errorId = "TODO"; + if (throwable instanceof EAAFException) + errorId = ((EAAFException) throwable).getErrorId(); + + log.info(buildLogMessage( + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + + + } + + @Override + public void logErrorOperation(Throwable throwable, IRequest errorRequest) { + String errorId = "TODO"; + if (throwable instanceof EAAFException) + errorId = ((EAAFException) throwable).getErrorId(); + + if (errorRequest != null) + log.info(buildLogMessage( + errorRequest.getUniqueTransactionIdentifier(), + errorRequest.getSPEntityId(), + errorRequest.getRawData(MSeIDASNodeConstants.DATA_REQUESTERID), + errorRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + + else + log.info(buildLogMessage( + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + + } + + @Override + public void internalTesting() throws Exception { + log.trace("Not implemented for a File-based logger"); + + } + + private String buildLogMessage(String tId, String moaIDEntityId, Object requesterId, String target, String cc, + String status, String errorCode, String errorMsg) { + String logMsg = StringUtils.EMPTY; + + //data,tId,MOAID-Id,SP-Id,bPKTarget,CC,status,error-code,error-msg + + logMsg += DateTime.now().toString(DATEFORMATER ) + ","; + logMsg += tId + ","; + logMsg += moaIDEntityId + ","; + + if (requesterId instanceof String && StringUtils.isNotEmpty((String)requesterId)) + logMsg += (String)requesterId + ","; + else + logMsg += StringUtils.EMPTY + ","; + + logMsg += target + ","; + logMsg += cc + ","; + + logMsg += status + ","; + logMsg += errorCode + ","; + logMsg += errorMsg; + + return logMsg; + } +} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/mapper/LoALevelMapper.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/mapper/LoALevelMapper.java index 9432931e..80cb6e20 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/mapper/LoALevelMapper.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/mapper/LoALevelMapper.java @@ -21,7 +21,7 @@ public class LoALevelMapper implements ILoALevelMapper{ @Override public String mapToeIDASLoA(String LoA) { - if (LoA.startsWith(EAAFConstants.EIDAS_QAA_PREFIX)) + if (LoA.startsWith(EAAFConstants.EIDAS_LOA_PREFIX)) return LoA; else diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/EvaluateCountrySelectionTask.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/EvaluateCountrySelectionTask.java index 1a8e1f6e..3fe7d5a0 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/EvaluateCountrySelectionTask.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/EvaluateCountrySelectionTask.java @@ -15,6 +15,7 @@ import at.gv.egiz.eaaf.core.api.data.EAAFConstants; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants; /** * @author tlenz @@ -29,19 +30,27 @@ public class EvaluateCountrySelectionTask extends AbstractAuthServletTask { public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { try { - // set parameter execution context - Enumeration<String> reqParamNames = request.getParameterNames(); - while(reqParamNames.hasMoreElements()) { - String paramName = reqParamNames.nextElement(); - if (StringUtils.isNotEmpty(paramName) && - !EAAFConstants.PROCESS_ENGINE_PENDINGREQUESTID.equalsIgnoreCase(paramName)) - executionContext.put(paramName, - StringEscapeUtils.escapeHtml(request.getParameter(paramName))); + + String stopAuthFlag = request.getParameter(MSeIDASNodeConstants.REQ_PARAM_STOP_PROCESS); + if (StringUtils.isNotEmpty(stopAuthFlag) && Boolean.parseBoolean(stopAuthFlag)) { + log.info("Authentication process WAS stopped by entity. Stopping auth. process ... "); + pendingReq.setAbortedByUser(true); + pendingReq.setAuthenticated(false); + + } else { + // set parameter execution context + Enumeration<String> reqParamNames = request.getParameterNames(); + while(reqParamNames.hasMoreElements()) { + String paramName = reqParamNames.nextElement(); + if (StringUtils.isNotEmpty(paramName) && + !EAAFConstants.PROCESS_ENGINE_PENDINGREQUESTID.equalsIgnoreCase(paramName)) + executionContext.put(paramName, + StringEscapeUtils.escapeHtml(request.getParameter(paramName))); + + } + log.info("Country selection finished. Starting auth. process for country ... "); } - - - log.info("Country selection finished. Starting auth. process for country ... "); } catch (Exception e) { log.warn("EvaluateBKUSelectionTask has an internal error", e); diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java index 86895729..6616de88 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java @@ -48,8 +48,7 @@ public class GenerateCountrySelectionFrameTask extends AbstractAuthServletTask { log.warn("Can not build GUI:'BKU-Selection'. Msg:" + e.getMessage()); throw new TaskExecutionException(pendingReq, "Can not build GUI. Msg:" + e.getMessage(), - new EAAFException("builder.09", new Object[]{e.getMessage()}, - "Can not build GUI:'BKU-Selection'. Msg:" + e.getMessage(), e)); + new EAAFException("gui.00", new Object[]{e.getMessage()}, e)); } catch (Exception e) { log.warn("FinalizeAuthenticationTask has an internal error", e); diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java index 57f6e373..475b8407 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java @@ -38,7 +38,16 @@ public class PVPMetadataProvider extends AbstractChainingMetadataProvider{ protected String getMetadataURL(String entityId) throws EAAFConfigurationException { ISPConfiguration spConfig = basicConfig.getServiceProviderConfiguration(entityId); if (spConfig != null) { - return spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_URL); + String metadataURL = entityId; + + String metadataURLFromConfig = spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_URL); + if (StringUtils.isNotEmpty(metadataURLFromConfig)) { + log.debug("Use metdataURL from configuration for EntityId: " + entityId); + metadataURL = metadataURLFromConfig; + + } + + return metadataURL; } else log.info("No ServiceProvider with entityId: " + entityId + " in configuration."); diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/StatusMessageProvider.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/StatusMessageProvider.java index 6e3f45cc..4bcc1ee6 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/StatusMessageProvider.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/StatusMessageProvider.java @@ -2,29 +2,103 @@ *******************************************************************************/ package at.gv.egiz.eidas.specific.connector.provider; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import at.gv.egiz.eaaf.core.api.IStatusMessager; +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.exceptions.EAAFException; @Service("StatusMessageProvider") -public class StatusMessageProvider implements IStatusMessager { - +public class StatusMessageProvider implements IStatusMessenger { + private static final Logger log = LoggerFactory.getLogger(StatusMessageProvider.class); + + private static final String ERROR_MESSAGES_UNAVAILABLE = "Error messages can NOT be load from application. Only errorCode: {0} is availabe" ; + private static final String ERROR_NO_MESSAGE = "No errormesseage for error with number.={0}"; + + private static final String ERROR_EXTERNALERROR_CODES_UNAVAILABLE = "External error-codes can NOT be load from application. Only internal errorCode: {0} is availabe" ; + private static final String ERROR_NO_EXTERNALERROR_CODE = "No external error for internal error with number.={0}"; + + //internal messanges + private static final String DEFAULT_MESSAGE_RESOURCES = "resources/properties/id_messages"; + private static final Locale DEFAULT_MESSAGE_LOCALES = new Locale("en", "GB"); + private ResourceBundle messages; + + //external error codes + private static final String DEFAULT_EXTERNALERROR_RESOURCES = "resources/properties/protocol_response_statuscodes"; + private static final Locale DEFAULT_EXTERNALERROR_LOCALES = new Locale("en", "GB"); + private ResourceBundle externalError = null; + @Override public String getMessage(String messageId, Object[] parameters) { - return "NOT IMPLEMENTED YET"; - + // initialize messages + if (messages == null) { + this.messages = PropertyResourceBundle.getBundle( + DEFAULT_MESSAGE_RESOURCES, + DEFAULT_MESSAGE_LOCALES); + + } + + // create the message + if (messages == null) { + return MessageFormat.format(ERROR_MESSAGES_UNAVAILABLE, new Object[] { messageId }); + + } else { + try { + String rawMessage = messages.getString(messageId); + return MessageFormat.format(rawMessage, parameters); + + } catch (MissingResourceException e2) { + return MessageFormat.format(ERROR_NO_MESSAGE, new Object[] { messageId }); + + } + } } @Override public String getResponseErrorCode(Throwable throwable) { - return "NOT IMPLEMENTED YET"; + String errorCode = IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + if (throwable instanceof EAAFException) { + errorCode = ((EAAFException) throwable).getErrorId(); + + } + //TODO: maybe more internal switches are required + + return errorCode; } @Override public String mapInternalErrorToExternalError(String intErrorCode) { - return "NOT IMPLEMENTED YET"; - + // initialize messages + if (externalError == null) { + this.externalError = PropertyResourceBundle.getBundle( + DEFAULT_EXTERNALERROR_RESOURCES, + DEFAULT_EXTERNALERROR_LOCALES); + + } + + // create the message + if (externalError == null) { + log.warn(MessageFormat.format(ERROR_EXTERNALERROR_CODES_UNAVAILABLE, new Object[] { intErrorCode })); + return IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } else { + try { + return externalError.getString(intErrorCode); + + } catch (MissingResourceException e2) { + log.info(MessageFormat.format(ERROR_NO_EXTERNALERROR_CODE, new Object[] { intErrorCode })); + return IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } + } } } diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/CacheWitheIDASBackend.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/CacheWitheIDASBackend.java new file mode 100644 index 00000000..7a62eca4 --- /dev/null +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/CacheWitheIDASBackend.java @@ -0,0 +1,33 @@ +package at.gv.egiz.eidas.specific.connector.storage; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import eu.eidas.auth.commons.cache.ConcurrentMapService; +import eu.eidas.auth.commons.tx.AbstractCorrelationMap; + +public class CacheWitheIDASBackend extends AbstractCorrelationMap<TransactionStoreElement> { + + protected CacheWitheIDASBackend(ConcurrentMapService concurrentMapService) { + super(concurrentMapService); + } + + public List<String> clean(Date now, long dataTimeOut) { + List<String> result = new ArrayList<String>(); + Iterator<String> iterator = map.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + if (map.containsKey(key)) { + TransactionStoreElement element = map.get(key); + if (now.getTime() - element.getCreated().getTime() > dataTimeOut) + result.add(key); + } + } + + return result; + + } + +} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java index e4d02dae..57697ef8 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java @@ -26,7 +26,10 @@ public class SimpleInMemoryTransactionStorage implements ITransactionStorage{ @Override public void changeKey(String oldKey, String newKey, Object value) throws EAAFException { if (containsKey(oldKey)) { - + TransactionStoreElement el = storage.get(oldKey); + el.setKey(newKey); + storage.put(newKey, el); + storage.remove(oldKey); } else throw new EAAFStorageException("No element in TransactionStorage with key: " + oldKey); diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/eIDASCacheTransactionStoreDecorator.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/eIDASCacheTransactionStoreDecorator.java new file mode 100644 index 00000000..6bc23073 --- /dev/null +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/storage/eIDASCacheTransactionStoreDecorator.java @@ -0,0 +1,124 @@ +package at.gv.egiz.eidas.specific.connector.storage; + +import java.util.Date; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException; + +public class eIDASCacheTransactionStoreDecorator implements ITransactionStorage{ + private static final Logger log = LoggerFactory.getLogger(eIDASCacheTransactionStoreDecorator.class); + + @Autowired(required=true) private CacheWitheIDASBackend storage; + + @Override + public void changeKey(String oldKey, String newKey, Object value) throws EAAFException { + if (containsKey(oldKey)) { + TransactionStoreElement el = storage.get(oldKey); + el.setKey(newKey); + storage.put(newKey, el); + storage.remove(oldKey); + + } else + throw new EAAFStorageException("No element in TransactionStorage with key: " + oldKey); + + } + + @Override + public List<String> clean(Date now, long dataTimeOut) { + return storage.clean(now, dataTimeOut); + + } + + @Override + public boolean containsKey(String key) { + if (key != null) { + if (storage.get(key) != null) + return true; + + } + + return false; + + } + + @Override + public Object get(String key) throws EAAFException { + if (key != null && containsKey(key)) { + TransactionStoreElement element = storage.get(key); + return element.getData(); + + } else + return null; + } + + @Override + public <T> T get(String key, Class<T> type) throws EAAFException { + return get(key, type, -1); + + } + + @Override + public <T> T get(String key, Class<T> type, long dataTimeOut) throws EAAFException { + if (key != null && containsKey(key)) { + TransactionStoreElement value = storage.get(key); + + if (dataTimeOut > -1) { + long now = new Date().getTime(); + if (now - value.getCreated().getTime() > dataTimeOut) { + log.info("Transaction-Data with key: " + key + " is out of time."); + throw new EAAFStorageException("Transaction-Data with key: " + key + " is out of time."); + + } + } + + if (type.isAssignableFrom(value.getData().getClass())) { + return (T) value.getData(); + + } else + log.warn("Can NOT cast '" + value.getClass() + "' to '" + type + "'"); + + } + + return null; + } + + @Override + public Object getRaw(String key) throws EAAFException { + return storage.get(key); + + } + + @Override + public void put(String key, Object value, int dataTimeOut) throws EAAFException { + TransactionStoreElement element = new TransactionStoreElement(); + element.setKey(key); + element.setData(value); + storage.put(key, element); + + } + + @Override + public void putRaw(String key, Object value) throws EAAFException { + if (value instanceof TransactionStoreElement) + storage.put(((TransactionStoreElement) value).getKey(), (TransactionStoreElement) value); + else + log.info(value.getClass().getName() + " is NOT a RAW element of " + ITransactionStorage.class.getName()); + + } + + @Override + public void remove(String key) { + if (containsKey(key)) { + log.debug("Remove element with key: " + key + " from " + ITransactionStorage.class.getName()); + storage.remove(key); + + } + } + +} diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java index 1b912ed4..0217eec4 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java @@ -60,11 +60,11 @@ public class AuthnRequestValidator implements IAuthnRequestValidator { String spEntityId = extractScopeRequsterId(authnReq); if (StringUtils.isEmpty(spEntityId)) { log.info("NO service-provider entityID in Authn. request. Stop authn. process ... "); - throw new AuthnRequestValidatorException("TODO", null, - "NO service-provider entityID in Authn. request", pendingReq); + throw new AuthnRequestValidatorException("pvp2.22", + new Object[] {"NO relaying-party entityID in Authn. request"}, pendingReq); } else - pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTERID, spEntityId); + pendingReq.setRawDataToTransaction(MSeIDASNodeConstants.DATA_REQUESTERID, spEntityId); //post-process ProviderName @@ -72,17 +72,15 @@ public class AuthnRequestValidator implements IAuthnRequestValidator { if (StringUtils.isEmpty(providerName)) log.info("Authn. request contains NO SP friendlyName"); else - pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_PROVIDERNAME, spEntityId); + pendingReq.setRawDataToTransaction(MSeIDASNodeConstants.DATA_PROVIDERNAME, spEntityId); - //TODO: set to SPConfiguration //post-process requested LoA List<String> reqLoA = extractLoA(authnReq); - pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTED_LOA_LIST, reqLoA); - - //TODO: set to SPConfiguration + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA(reqLoA); + //post-process requested LoA comparison-level String reqLoAComperison = extractComparisonLevel(authnReq); - pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTED_LOA_COMPERISON, reqLoAComperison); + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode(reqLoAComperison); //validate and process requested attributes boolean sectorDetected = false; @@ -124,15 +122,13 @@ public class AuthnRequestValidator implements IAuthnRequestValidator { if (!sectorDetected) { log.info("Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information."); - throw new AuthnRequestValidatorException("TODO", null, - "Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information."); + throw new AuthnRequestValidatorException("pvp2.22", new Object[] {"NO or NO VALID target-sector information"}); } } catch (EAAFStorageException e) { log.info("Can NOT store Authn. Req. data into pendingRequest." , e); - throw new AuthnRequestValidatorException("TODO", null, - "Can NOT store Authn. Req. data into pendingRequest.", e); + throw new AuthnRequestValidatorException("internal.02", null, e); } @@ -159,9 +155,9 @@ public class AuthnRequestValidator implements IAuthnRequestValidator { } else if (authContext.getAuthnContextClassRefs().size() > 1) { log.info("Authn. Req. contains MORE THAN ONE requested LoA, but " + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one" ); - throw new AuthnRequestValidatorException("TODO", null, - "Authn. Req. contains MORE THAN ONE requested LoA, but " - + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one"); + throw new AuthnRequestValidatorException("pvp2.22", + new Object[] {"Authn. Req. contains MORE THAN ONE requested LoA, but " + + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one"}); } else result.add(authContext.getAuthnContextClassRefs().get(0).getAuthnContextClassRef()); @@ -173,9 +169,9 @@ public class AuthnRequestValidator implements IAuthnRequestValidator { } else { log.info("Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '" + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported"); - throw new AuthnRequestValidatorException("TODO", null, - "Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '" - + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported"); + throw new AuthnRequestValidatorException("pvp2.22", + new Object[] {"Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '" + + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported"}); } diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java index d7d75f90..20d419af 100644 --- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java +++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java @@ -62,11 +62,13 @@ public class MetadataSignatureVerificationFilter extends AbstractMetadataSignatu } else - throw new PVP2MetadataException("Can not open trustStore: " + trustStorePath + " for metadata: " + metadataURL, null); + throw new PVP2MetadataException("pvp2.26", + new Object[] {"Can not open trustStore: " + trustStorePath + " for metadata: " + metadataURL}); } catch (KeyStoreException | IOException e) { log.warn("Can not open trustStore: " + trustStorePath + " for metadata: " + metadataURL + " Reason: " + e.getMessage(), e); - throw new PVP2MetadataException("Can not open trustStore: " + trustStorePath + " for metadata", null, e); + throw new PVP2MetadataException("pvp2.26", + new Object[] {"Can not open trustStore: " + trustStorePath + " for metadata"}, e); } @@ -81,20 +83,23 @@ public class MetadataSignatureVerificationFilter extends AbstractMetadataSignatu } catch (EAAFException e) { log.info("Metadata verification FAILED for: " + metadataURL + " Reason: " +e.getMessage()); - throw new PVP2MetadataException("Metadata verification FAILED for: " + metadataURL + " Reason: " +e.getMessage(), null, e); + throw new PVP2MetadataException("pvp2.26", + new Object[] {"Metadata verification FAILED for: " + metadataURL + " Reason: " +e.getMessage()}, e); } } @Override protected void verify(EntitiesDescriptor desc) throws PVP2MetadataException { - throw new PVP2MetadataException("EntitiesDescritors are NOT supported", null); + throw new PVP2MetadataException("pvp2.26", + new Object[] {"EntitiesDescritors are NOT supported"}); } @Override protected void verify(EntityDescriptor entity, EntitiesDescriptor desc) throws PVP2MetadataException { - throw new PVP2MetadataException("EntitiesDescritors are NOT supported", null); + throw new PVP2MetadataException("pvp2.26", + new Object[] {"EntitiesDescritors are NOT supported"}); } diff --git a/connector/src/main/resources/applicationContext.xml b/connector/src/main/resources/applicationContext.xml index 5ede0b7f..c44c903e 100644 --- a/connector/src/main/resources/applicationContext.xml +++ b/connector/src/main/resources/applicationContext.xml @@ -25,6 +25,8 @@ <bean class="at.gv.egovernment.moa.id.auth.servlet.interceptor.UniqueSessionIdentifierInterceptor" /> </mvc:interceptors> --> + <context:property-placeholder location="${eidas.ms.configuration}"/> + <bean id="BasicMSSpecificNodeConfig" class="at.gv.egiz.eidas.specific.connector.config.BasicConfigurationProvider"> <constructor-arg value="#{systemProperties['eidas.ms.configuration']}"/> diff --git a/connector/src/main/resources/properties/external_statuscodes_map.properties b/connector/src/main/resources/properties/external_statuscodes_map.properties new file mode 100644 index 00000000..45f622c8 --- /dev/null +++ b/connector/src/main/resources/properties/external_statuscodes_map.properties @@ -0,0 +1,71 @@ +eidas.00=1302 +eidas.01=1302 +eidas.02=1301 +eidas.03=1300 +eidas.04=1100 +eidas.05=1302 +eidas.06=1302 +eidas.07=1302 + +config.01=9099 +config.03=9099 +config.18=9099 +config.24=9099 + + +ernb.00=4601 +ernb.01=4601 +ernb.02=4600 + +auth.00=1100 + +auth.21=1005 +auth.26=1100 +auth.28=1100 + +auth.37=1101 +auth.38=1101 +auth.39=1099 + +process.01=9105 +process.02=9104 +process.03=9104 +process.04=9105 + +builder.00=9102 +builder.11=1099 + +parser.01=1101 + +gui.00=9103 + +pvp2.01=6100 +pvp2.02=6100 +pvp2.05=6105 +pvp2.07=6104 +pvp2.09=6199 +pvp2.10=6100 +pvp2.11=6105 +pvp2.12=6105 +pvp2.13=6199 +pvp2.14=6199 +pvp2.15=6103 +pvp2.16=6101 +pvp2.17=6102 +pvp2.20=6103 +pvp2.21=6104 +pvp2.22=6105 +pvp2.23=6105 +pvp2.24=6105 +pvp2.26=6103 +pvp2.27=6199 +pvp2.28=6105 + + +internal.00=9105 +internal.01=9199 +internal.02=9101 +internal.03=9199 +internal.04=9101 + +config.27=9008
\ No newline at end of file diff --git a/connector/src/main/resources/properties/status_messages_en.properties b/connector/src/main/resources/properties/status_messages_en.properties new file mode 100644 index 00000000..7499f99d --- /dev/null +++ b/connector/src/main/resources/properties/status_messages_en.properties @@ -0,0 +1,69 @@ +eidas.00=eIDAS Attribute {0} not found. Can not finish authentication process +eidas.01=NO eIDAS response-message found. Can not finish authentication process +eidas.02=eIDAS response-message contains an error. ErrorCode: {0}, ErrorMsg: {1} +eidas.03=No CitizenCountry available. Can not start eIDAS authentication process +eidas.04=Request contains no sessionToken. Authentication process stops +eidas.05=Received eIDAS response-message is not valid. Reason: {0} +eidas.06=LoA from eIDAS response-message {0} does not match to requested LoA +eidas.07=eIDAS Response attribute-validation FAILED. Attribute:{0} Reason: {1} + +config.01=No configuration-file parameter found. Maybe Java SystemD parameter is missing +config.03=Can not load configuration from path {0} (See logs for more details) +config.18=Configuration file {0} is not available on filesystem +config.24=Configuration file {1} does not start with {0} prefix. + + +ernb.00=Receive no identity-link from SZR +ernb.01=Receive no bPK from SZR +ernb.02=SZR response contains an error. ErrorMsg: {0} + +auth.00=Service provider: {0} is unknown +auth.21=The authentication process was stopped by user +auth.26=No transaction identifier +auth.28=Found no active transaction with Id: {0}. Maybe, the transaction was removed after timeout +auth.37=Requested bPK-Target: {0} does not match allowed targets for service provider: {1} +auth.38=Passive authentication was requested but user as no active session +auth.39=Error: '{0}' in post-processing of authentication data. Can not finish authentication process + +process.01=Can not execute authentication process +process.02=Find no applicable authentication process for transaction with Id: {0} +process.03=Can not resume the authentication process. Reason: {0} +process.04=Can not execute authentication process. Problem with an internal state + +builder.00=Can not generate data structure "{0}": {1} +builder.11=Error: '{0}' in post-processing of authentication data. Can not finish authentication process + +parser.01=Error during eID-data processing. Reason: {0} + +gui.00=Can not build GUI component. Reason: {0} + +pvp2.01=General error during SAML2 response encoding +pvp2.02=SAML2 attribute contains an wrong encoded value +pvp2.05=LoA from SAML2 Authn. request: {0} is not supported +pvp2.07=SAML2 Authn. request contains is not signed +pvp2.09=SAML2 request contains an unsupported operation. (OperationId: {0}) +pvp2.10=SAML2 Attribute: {0} is not available +pvp2.11=SAML2 Binding: {0} is not supported +pvp2.12=SAML2 NameID Format {0} is not supported +pvp2.13=Internal server error during SAML2 processing +pvp2.14=SAML2 authentication not available +pvp2.15=No SAML2 metadata available or metadata processing failed +pvp2.16=Encryption of SAML2 assertion failed +pvp2.17=LoA from SAML2 Authn. request: {1} does not match to authenticated LoA: {0} by using matching-mode: {2} +pvp2.20=SAML2 Authn. request contains an unknown or empty EntityID. +pvp2.21=Signature validation of SAML2 Authn. request failed. Reason: {0} +pvp2.22=Validation of SAML2 Authn. request failed. Reason: {0} +pvp2.23=Validation of SAML2 Authn. request failed. Reason: AssertionConsumerServiceURL {0} is not valid. +pvp2.24=General error during SAML2 Auth. request pre-processing. Reason: {0} +pvp2.26=SAML2 metadata validation failed. Reason: {0} +pvp2.27=General error during SAML2 metadata generation +pvp2.28=Validation of SAML2 Authn. request failed. Reason: AssertionConsumerServiceIndex {0} is not valid. + + +internal.00=The authentication process stops by reason of an internal problem +internal.01=The LogOut process stops by reason of an internal problem +internal.02=Internal error. Can not access data cache. +internal.03=Internal error. Can not initialize a cryptographic method. +internal.04=Internal error. Can not access data cache (Reason: {0}). + +config.27=Configuration parameter processing failed. Reason:{0} diff --git a/connector/src/main/resources/specific_eIDAS_connector.beans.xml b/connector/src/main/resources/specific_eIDAS_connector.beans.xml index 16a1cae7..275c79b8 100644 --- a/connector/src/main/resources/specific_eIDAS_connector.beans.xml +++ b/connector/src/main/resources/specific_eIDAS_connector.beans.xml @@ -17,11 +17,7 @@ <bean id="ProcessEngineSignalController" class="at.gv.egiz.eidas.specific.connector.controller.ProcessEngineSignalController"/> - - - <bean id="SimpleInMemoryTransactionStorage" - class="at.gv.egiz.eidas.specific.connector.storage.SimpleInMemoryTransactionStorage" /> - + <bean id="AuthenticationManager" class="at.gv.egiz.eidas.specific.connector.auth.AuthenticationManager" /> @@ -82,11 +78,11 @@ <bean id="StatusMessageProvider" class="at.gv.egiz.eidas.specific.connector.provider.StatusMessageProvider" /> - <bean id="DummyRevisionLogger" - class="at.gv.egiz.eaaf.core.impl.logging.DummyRevisionsLogger" /> + <bean id="eidasRevisionLogger" + class="at.gv.egiz.eidas.specific.connector.logger.RevisionLogger" /> - <bean id="DummyStatisticLogger" - class="at.gv.egiz.eaaf.core.impl.logging.DummyStatisticLogger" /> + <bean id="eidasStatisticLogger" + class="at.gv.egiz.eidas.specific.connector.logger.StatisticLogger" /> <!-- Tasks --> diff --git a/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml b/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml new file mode 100644 index 00000000..be13e0cf --- /dev/null +++ b/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xmlns:mvc="http://www.springframework.org/schema/mvc" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd + http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> + + <import resource="classpath:specificCommunicationDefinitionApplicationContext.xml"/> + + <bean id="useDistributedMapsSpecificConnector" class="java.lang.String"> + <constructor-arg value="${eidas.ms.context.use.clustermode}"/> + </bean> + + <!-- suffix for some of the beans having two possible implementations - one for development and one for production --> + <bean id="distributedEnvSuffixSpecificConnector" class="java.lang.String"> + <constructor-arg value="#{useDistributedMapsSpecificConnector.toString()=='false'?'Dev':'Prod'}"/> + </bean> + + +<!-- <bean id="SimpleInMemoryTransactionStorage" + class="at.gv.egiz.eidas.specific.connector.storage.SimpleInMemoryTransactionStorage" /> --> + + <bean id="eIDASCacheTransactionStoreDecorator" + class="at.gv.egiz.eidas.specific.connector.storage.eIDASCacheTransactionStoreDecorator"/> + + <bean id="CacheWitheIDASBackend" class="at.gv.egiz.eidas.specific.connector.storage.CacheWitheIDASBackend"> + <constructor-arg ref="springServiceCMapspecificMSSpCorProvider#{distributedEnvSuffixSpecificConnector.toString()}"/> + </bean> + + <bean id="defaultHazelcastInstance" class="java.lang.String"> + <constructor-arg value="eidasHazelcastInstance"/> + </bean> + + <bean id="eidasHazelcastInstanceInitializer" class=" eu.eidas.auth.commons.cache.HazelcastInstanceInitializer" init-method="initializeInstance" lazy-init="true"> + <property name="hazelcastConfigfileName" value="#{eidasConfigRepository}hazelcast.xml"/> + <property name="hazelcastInstanceName" ref="defaultHazelcastInstance"/> + </bean> + + <bean id="springServiceCMapspecificMSSpCorProviderProd" class="eu.eidas.auth.commons.cache.ConcurrentMapServiceDistributedImpl" lazy-init="true"> + <property name="hazelcastInstanceInitializer" ref="eidasHazelcastInstanceInitializer"/> + <property name="cacheName" value="specificSpRequestCorrelationCacheService"/> + </bean> + + <bean id="springServiceCMapspecificMSSpCorProviderDev" class="eu.eidas.auth.commons.cache.ConcurrentMapServiceDefaultImpl"> + <property name="expireAfterAccess" value="1800"/> + <property name="maximumSize" value="1000"/> + </bean> + +</beans>
\ No newline at end of file diff --git a/connector/src/main/webapp/autocommit.js b/connector/src/main/webapp/autocommit.js new file mode 100644 index 00000000..d21a5651 --- /dev/null +++ b/connector/src/main/webapp/autocommit.js @@ -0,0 +1,5 @@ +function autoCommmit() { + document.forms[0].submit(); +} + +document.addEventListener('DOMContentLoaded', autoCommmit);
\ No newline at end of file diff --git a/connector/src/main/webapp/basic.css b/connector/src/main/webapp/basic.css new file mode 100644 index 00000000..4bec163a --- /dev/null +++ b/connector/src/main/webapp/basic.css @@ -0,0 +1,4 @@ +@charset "utf-8"; + .bgTrans { + background-color:transparent + }
\ No newline at end of file |