diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2021-01-11 15:42:26 +0100 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2021-01-11 15:42:26 +0100 | 
| commit | c77fcb3e75da79647f099216c3478ecdf219a120 (patch) | |
| tree | 38444e5b15cfb1705f87b150aec200976bc22ee5 /connector/src | |
| parent | c9de974247b23c2ac0a997ef25f70b9a75cd1aaf (diff) | |
| parent | a5d2e6d6fa2c75ae8211c818537524e8c54c3129 (diff) | |
| download | National_eIDAS_Gateway-c77fcb3e75da79647f099216c3478ecdf219a120.tar.gz National_eIDAS_Gateway-c77fcb3e75da79647f099216c3478ecdf219a120.tar.bz2 National_eIDAS_Gateway-c77fcb3e75da79647f099216c3478ecdf219a120.zip | |
Merge branch 'feature/springboot' into 'nightlybuild'
Feature/springboot
See merge request egiz/eidas_at_proxy!7
Diffstat (limited to 'connector/src')
45 files changed, 2103 insertions, 629 deletions
| diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificEidasNodeSpringResourceProvider.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificEidasNodeSpringResourceProvider.java index 6e8e06ef..40ed283b 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificEidasNodeSpringResourceProvider.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificEidasNodeSpringResourceProvider.java @@ -32,11 +32,15 @@ public class MsSpecificEidasNodeSpringResourceProvider implements SpringResource    @Override    public Resource[] getResourcesToLoad() { -    final ClassPathResource msEidasNode = new ClassPathResource("/specific_eIDAS_connector.beans.xml", -        MsSpecificEidasNodeSpringResourceProvider.class); +    final ClassPathResource generic = +        new ClassPathResource("/applicationContext.xml", MsSpecificEidasNodeSpringResourceProvider.class); +     +    final ClassPathResource msEidasNode = new ClassPathResource( +        "/specific_eIDAS_connector.beans.xml", MsSpecificEidasNodeSpringResourceProvider.class); +          final ClassPathResource msEidasNodeStorage = new ClassPathResource(          "/specific_eIDAS_connector.storage.beans.xml", MsSpecificEidasNodeSpringResourceProvider.class); -    return new Resource[] { msEidasNode, msEidasNodeStorage }; +    return new Resource[] { generic, msEidasNode, msEidasNodeStorage };    }    @Override diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificSpringBootApplicationContextInitializer.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificSpringBootApplicationContextInitializer.java new file mode 100644 index 00000000..399d1286 --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/MsSpecificSpringBootApplicationContextInitializer.java @@ -0,0 +1,82 @@ +package at.asitplus.eidas.specific.connector; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertiesPropertySource; + +import at.gv.egiz.components.spring.api.SpringBootApplicationContextInitializer; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MsSpecificSpringBootApplicationContextInitializer extends +    SpringBootApplicationContextInitializer { + +  private static final String SYSTEMD_PROP_NAME = "eidas.ms.configuration"; +  private static final String PATH_FILE_PREFIX = "file:"; +   +  @Override +  public void initialize(ConfigurableApplicationContext applicationContext) {     +    String configPath = System.getProperty(SYSTEMD_PROP_NAME); +    if (StringUtils.isNotEmpty(configPath)) { +      log.debug("Find configuration-source from SystemD Property: '{}' ...", SYSTEMD_PROP_NAME);       +      if (configPath.startsWith(PATH_FILE_PREFIX)) { +        configPath = configPath.substring(PATH_FILE_PREFIX.length()); +         +      }       +      injectConfiguration(configPath, applicationContext);             + +    } else { +      log.info("Find NO SystemD Property: '{}' Maybe no configuration available", SYSTEMD_PROP_NAME); +       +    } +     +    super.initialize(applicationContext); +         +  } +   +  private void injectConfiguration(String configPath, ConfigurableApplicationContext applicationContext) { +    InputStream is = null; +    try { +      Path path = Paths.get(configPath); +      if (Files.exists(path)) { +        File file = new File(configPath);              +        Properties props = new Properties(); +        is = new FileInputStream(file); +        props.load(is);       +        MutablePropertySources sources = applicationContext.getEnvironment().getPropertySources();        +        sources.addFirst(new PropertiesPropertySource(SYSTEMD_PROP_NAME, props)); +        log.info("Set configuration-source from SystemD-Property: {}", SYSTEMD_PROP_NAME); +       +      } else { +        log.error("Configuration from SystemD Property: '{}' at Location: {} DOES NOT exist",  +            SYSTEMD_PROP_NAME, configPath); +         +      } +       +    } catch (IOException e) { +      log.error("Configuration from SystemD Property: '{}' at Location: {} CAN NOT be loaded",  +          SYSTEMD_PROP_NAME, configPath, e); +       +    } finally { +      try { +        if (is != null) { +          is.close(); +           +        }         +      } catch (IOException e) { +        log.error("Can not close InputStream of configLoader: {}", configPath, e); +         +      } +    }         +  } +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringBootApplicationInitializer.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringBootApplicationInitializer.java new file mode 100644 index 00000000..428f5f56 --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringBootApplicationInitializer.java @@ -0,0 +1,105 @@ +package at.asitplus.eidas.specific.connector; + +import org.opensaml.core.config.InitializationException; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.web.context.WebApplicationContext; + +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; +import at.gv.egiz.eaaf.core.impl.logging.SimpleStatusMessager; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + +@Slf4j +@SpringBootApplication(scanBasePackages = { +    "at.asitplus.eidas.specific.connector",  +    "at.gv.egiz.eaaf.utils.springboot.ajp" +    }) +public class SpringBootApplicationInitializer extends SpringBootServletInitializer { + +  private static ConfigurableApplicationContext ctx; + +  /** +   * Starts MS-specific eIDAS-Implementation SpringBoot application. +   * +   * @param args Starting parameters +   * @throws Throwable In case of a start-up error +   */ +  public static void main(final String[] args) throws Throwable { +    try { +      log.info("=============== Initializing Spring-Boot context! ==============="); +      LogMessageProviderFactory.setStatusMessager(new SimpleStatusMessager()); +      final SpringApplication springApp = +          new SpringApplication(SpringBootApplicationInitializer.class); +      springApp.addInitializers(new MsSpecificSpringBootApplicationContextInitializer()); + +      log.info("Bootstrap openSAML .... "); +      EaafOpenSaml3xInitializer.eaafInitialize(); +       +      log.debug("Run SpringBoot initialization process ... "); +      ctx = springApp.run(args); + +      // initialize status messenger +      LogMessageProviderFactory.setStatusMessager(ctx.getBean(IStatusMessenger.class)); +       +      log.info("Initialization of MS-specific eIDAS-Implementation finished."); + +    } catch (final Throwable e) { +      log.error("MS-specific eIDAS-Implementation initialization FAILED!", e); +      throw e; + +    } + +  } + +   +  protected SpringApplicationBuilder createSpringApplicationBuilder() {     +    try { +      log.info("Bootstrap openSAML .... "); +      EaafOpenSaml3xInitializer.eaafInitialize(); +            +    } catch (InitializationException | ComponentInitializationException e) { +      throw new RuntimeException(e); +       +    } +     +    SpringApplicationBuilder builder = new SpringApplicationBuilder(); +    builder.initializers(new MsSpecificSpringBootApplicationContextInitializer());     +    return builder; +     +  } +   +  protected WebApplicationContext run(SpringApplication application) { +    WebApplicationContext internalContext = (WebApplicationContext) application.run(); +    +    // initialize status messenger +    LogMessageProviderFactory.setStatusMessager(internalContext.getBean(IStatusMessenger.class)); +    +    log.info("Initialization of MS-specific eIDAS-Implementation finished."); +     +    return internalContext; +  } +   +  /** +   * Stops SpringBoot application of MS-specific eIDAS-Implementation. +   *  +   */ +  public static void exit() { +    if (ctx != null) { +      log.info("Stopping SpringBoot application ... "); +      SpringApplication.exit(ctx, () -> 0); +      ctx = null; +       +    } else { +      log.info("No SpringBoot context. Nothing todo"); +       +    } + +  } + +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringContextCloseHandler.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringContextCloseHandler.java new file mode 100644 index 00000000..e884b5c6 --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringContextCloseHandler.java @@ -0,0 +1,170 @@ +package at.asitplus.eidas.specific.connector; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.slf4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import at.gv.egiz.components.spring.api.IDestroyableObject; +import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; + +/** + * SpringContext CloseHandler. + * + * @author tlenz + * + */ + +public class SpringContextCloseHandler +    implements ApplicationListener<ContextClosedEvent>, ApplicationContextAware, BeanPostProcessor { + +  private static final Logger log = +      org.slf4j.LoggerFactory.getLogger(SpringContextCloseHandler.class); + +  private ApplicationContext context; + +  /* +   * (non-Javadoc) +   * +   * @see org.springframework.context.ApplicationListener#onApplicationEvent(org. +   * springframework.context. ApplicationEvent) +   */ +  @Override +  @EventListener +  public void onApplicationEvent(final ContextClosedEvent arg0) { +    log.info("MS-specific eIDAS-Node shutdown process started ..."); + +    try { +      log.debug("CleanUp objects with implements the IDestroyable interface ... "); +      final Map<String, IDestroyableObject> objectsToDestroy = +          context.getBeansOfType(IDestroyableObject.class); +      internalIDestroyableObject(objectsToDestroy); +      log.info("Object cleanUp complete"); + +      log.debug("Stopping Spring Thread-Pools ... "); +      // shut-down task schedulers +      final Map<String, ThreadPoolTaskScheduler> schedulers = +          context.getBeansOfType(ThreadPoolTaskScheduler.class); +      internalThreadPoolTaskScheduler(schedulers); + +      // shut-down task executors +      final Map<String, ThreadPoolTaskExecutor> executers = +          context.getBeansOfType(ThreadPoolTaskExecutor.class); +      internalThreadPoolTaskExecutor(executers); +      log.debug("Spring Thread-Pools stopped"); +       +       +      //clean-up eIDAS node +      Map<String, IgniteInstanceInitializerSpecificCommunication> nodeIgnite =  +          context.getBeansOfType(IgniteInstanceInitializerSpecificCommunication.class); +      log.info("Find #{} Apache Ignite instances from eIDAS Ref. impl.", nodeIgnite.size()); +      for (Entry<String, IgniteInstanceInitializerSpecificCommunication> el : nodeIgnite.entrySet()) { +        if (el.getValue().getInstance() != null) { +          el.getValue().getInstance().close(); +          el.getValue().destroyInstance(); +          log.debug("Shutdown Apache-Ignite: {}", el.getKey()); +           +        }         +      } +             +      log.info("MS-specific eIDAS-Node shutdown process finished"); + +    } catch (final Exception e) { +      log.warn("MS-specific eIDAS-Node shutdown process has an error.", e); + +    } + +  } + +  /* +   * (non-Javadoc) +   * +   * @see org.springframework.beans.factory.config.BeanPostProcessor# +   * postProcessAfterInitialization(java. lang.Object, java.lang.String) +   */ +  @Override +  public Object postProcessAfterInitialization(final Object arg0, final String arg1) +      throws BeansException { +    if (arg0 instanceof ThreadPoolTaskScheduler) { +      ((ThreadPoolTaskScheduler) arg0).setWaitForTasksToCompleteOnShutdown(true); +    } +    if (arg0 instanceof ThreadPoolTaskExecutor) { +      ((ThreadPoolTaskExecutor) arg0).setWaitForTasksToCompleteOnShutdown(true); +    } +    return arg0; + +  } + +  /* +   * (non-Javadoc) +   * +   * @see org.springframework.beans.factory.config.BeanPostProcessor# +   * postProcessBeforeInitialization(java .lang.Object, java.lang.String) +   */ +  @Override +  public Object postProcessBeforeInitialization(final Object arg0, final String arg1) +      throws BeansException { +    return arg0; + +  } + +  /* +   * (non-Javadoc) +   * +   * @see +   * org.springframework.context.ApplicationContextAware#setApplicationContext(org +   * .springframework. context.ApplicationContext) +   */ +  @Override +  public void setApplicationContext(final ApplicationContext arg0) throws BeansException { +    this.context = arg0; + +  } + +  private void internalThreadPoolTaskExecutor(final Map<String, ThreadPoolTaskExecutor> executers) { +    for (final ThreadPoolTaskExecutor executor : executers.values()) { +      executor.shutdown(); +      log.debug("Executer {} with active {} work has killed", executor.getThreadNamePrefix(), +          executor.getActiveCount()); + +    } + +  } + +  // Not required at the moment +  private void internalThreadPoolTaskScheduler( +      final Map<String, ThreadPoolTaskScheduler> schedulers) { +    log.trace("Stopping #{} task-schedulers", schedulers.size()); +     +  } + +  private void internalIDestroyableObject(final Map<String, IDestroyableObject> objectsToDestroy) { +    if (objectsToDestroy != null) { +      final Iterator<Entry<String, IDestroyableObject>> interator = +          objectsToDestroy.entrySet().iterator(); +      while (interator.hasNext()) { +        final Entry<String, IDestroyableObject> object = interator.next(); +        try { +          object.getValue().fullyDestroy(); +          log.debug("Object with ID: {} is destroyed", object.getKey()); + +        } catch (final Exception e) { +          log.warn("Destroing object with ID: {} FAILED!", object.getKey(), null, e); + +        } +      } +    } + +  } + +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringInitializer.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringInitializer.java deleted file mode 100644 index 417828a6..00000000 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringInitializer.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2018 A-SIT Plus GmbH - * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, - * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "License"); - * You may not use this work except in compliance with the License. - * You may obtain a copy of the License at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. -*/ - -package at.asitplus.eidas.specific.connector; - -import java.util.Arrays; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.core.io.ClassPathResource; -import org.springframework.web.WebApplicationInitializer; -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.request.RequestContextListener; -import org.springframework.web.context.support.GenericWebApplicationContext; -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.EaafOpenSaml3xInitializer; - -/** - * Web application initializer. - * - * @author Thomas Lenz - */ -public class SpringInitializer implements WebApplicationInitializer { - -  private static final Logger log = LoggerFactory.getLogger(SpringInitializer.class); - -  private String[] rootServletContexts = null; -  private String[] servletContexts = null; - -  /** -   * Application specific Spring initializer. -   *   -   */ -  public SpringInitializer() { -    this.rootServletContexts = null; -    this.servletContexts = new String[] { -        "/applicationContext.xml", - -    }; -  } - -  /* -   * (non-Javadoc) -   *  -   * @see -   * org.springframework.web.WebApplicationInitializer#onStartup(javax.servlet. -   * ServletContext) -   */ -  @Override -  public void onStartup(ServletContext servletContext) throws ServletException { -    try { -      log.info("=============== Loading Config Root Context! ==============="); -      final ApplicationContext cfgRootContext = -          new ClassPathXmlApplicationContext(new String[] { -              "/applicationContext.xml" -          }); - -      log.info("=============== Loading Root Context! ==============="); -      final GenericWebApplicationContext rootContext = new GenericWebApplicationContext(); -      rootContext.setServletContext(servletContext); -      rootContext.setParent(cfgRootContext); - -      log.info("Spring-context was initialized with active profiles: {}",  -          Arrays.asList(rootContext.getEnvironment().getActiveProfiles())); - -      log.info("=============== Loading Local Contexts! ==============="); -      final XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader( -          rootContext); -      if (rootServletContexts != null) { -        for (final String rootServletContext : rootServletContexts) { -          log.debug("Loading: " + rootServletContext); -          xmlReader.loadBeanDefinitions(new ServletContextResource( -              servletContext, rootServletContext)); -        } -      } -      // Manage the lifecycle of the root application context -      servletContext.addListener(new ContextLoaderListener(rootContext)); - -      // log.debug("Beans after logAMQP in {}", rootContext); -      // dumpBeanDefinitions(rootContext); - -      log.info("=============== Loading SPI Context! ==============="); -      log.debug("Loading modules and components"); -      SpringLoader.loadSpringServices(rootContext); - -      log.trace("Beans after SPI in " + rootContext); -      dumpBeanDefinitions(rootContext); - -      log.debug("Loading servlet config in " + rootContext); -      if (servletContexts != null) { -        for (final String servletContextString : servletContexts) { -          xmlReader.loadBeanDefinitions(new ClassPathResource(servletContextString, SpringInitializer.class)); -        } - -      } - -      log.debug("Refreshing context " + rootContext); -      rootContext.refresh(); - -      log.info("=============== Register Dispatcher Servlet! ==============="); - -      log.trace("Final Beans in " + rootContext); -      dumpBeanDefinitions(rootContext); - -      log.info("Registering dispatcher configuration"); -      final ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", -          new DispatcherServlet(rootContext)); -      if (dispatcher != null) { -        dispatcher.setLoadOnStartup(1); -        dispatcher.addMapping("/"); -        dispatcher.setAsyncSupported(true); - -      } else { -        log.error("Failed to register dispatcher server in servlet context!"); -      } - -      log.info("=============== Register RequestContextListener! ==============="); -      servletContext.addListener(new RequestContextListener()); - -      // initialize status messenger -      LogMessageProviderFactory.setStatusMessager(rootContext.getBean(IStatusMessenger.class)); - -      log.info("Bootstrap openSAML .... "); -      EaafOpenSaml3xInitializer.eaafInitialize(); - -      log.info("Seed random number generator ... "); -      Random.seedRandom(); - -      log.info("Initialization of MS-specific eIDAS-connector finished."); - -    } catch (final Throwable e) { -      log.error("MS-specific eIDAS-connector initialization FAILED!", e); - -    } - -  } - -  private void dumpBeanDefinitions(GenericApplicationContext context) { -    log.trace("Registered Bean in context " + context.toString()); - -    final String[] registeredBeans = context.getBeanDefinitionNames(); -    for (final String registeredBean : registeredBeans) { -      final BeanDefinition beanDefinition = context -          .getBeanDefinition(registeredBean); -      log.trace(registeredBean + " -> " + beanDefinition.getBeanClassName()); - -    } - -    log.trace("Registered Bean in context --" + context); -  } -} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/attributes/AuthBlockAttributeBuilder.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/attributes/AuthBlockAttributeBuilder.java index be9f8862..1833f377 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/attributes/AuthBlockAttributeBuilder.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/attributes/AuthBlockAttributeBuilder.java @@ -22,6 +22,9 @@ package at.asitplus.eidas.specific.connector.attributes;  import static at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.EID_AUTHBLOCK_SIGNED_FRIENDLY_NAME;  import static at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.EID_AUTHBLOCK_SIGNED_NAME; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +  import org.apache.commons.lang3.StringUtils;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; @@ -48,7 +51,8 @@ public class AuthBlockAttributeBuilder implements IPvpAttributeBuilder {      String authBlock = authData.getGenericData(Constants.SZR_AUTHBLOCK, String.class);      if (StringUtils.isNotEmpty(authBlock)) { -      return g.buildStringAttribute(EID_AUTHBLOCK_SIGNED_FRIENDLY_NAME, EID_AUTHBLOCK_SIGNED_NAME, authBlock); +      return g.buildStringAttribute(EID_AUTHBLOCK_SIGNED_FRIENDLY_NAME, EID_AUTHBLOCK_SIGNED_NAME,  +          Base64.getEncoder().encodeToString(authBlock.getBytes(StandardCharsets.UTF_8)));      } else {        throw new UnavailableAttributeException(EID_AUTHBLOCK_SIGNED_NAME); diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/config/StaticResourceConfiguration.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/config/StaticResourceConfiguration.java index 2a10031b..a1e953f1 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/config/StaticResourceConfiguration.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/config/StaticResourceConfiguration.java @@ -24,6 +24,7 @@  package at.asitplus.eidas.specific.connector.config;  import java.net.MalformedURLException; +import java.util.List;  import org.apache.commons.lang3.StringUtils;  import org.slf4j.Logger; @@ -35,11 +36,11 @@ import org.springframework.context.support.ReloadableResourceBundleMessageSource  import org.springframework.web.servlet.config.annotation.EnableWebMvc;  import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;  import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.i18n.CookieLocaleResolver;  import org.thymeleaf.templateresolver.FileTemplateResolver;  import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;  import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;  import at.gv.egiz.eaaf.core.impl.utils.FileUtils;  /** @@ -90,43 +91,63 @@ public class StaticResourceConfiguration implements WebMvcConfigurer {    }    /** -   * Internal i18n message source. -   *  +   * Get a message source with only internal message properties. +   * +   * @param ressourceLocations List of source-locations     * @return     */    @Bean -  public ReloadableResourceBundleMessageSource internalMessageSource() { -    final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); +  public ReloadableResourceBundleMessageSource internalMessageSource( +      @Autowired(required = false) final List<IMessageSourceLocation> ressourceLocations) { +    final ReloadableResourceBundleMessageSource messageSource = +        new ReloadableResourceBundleMessageSource();      // add default message source      messageSource.setBasename(DEFAULT_MESSAGE_SOURCE); + +    if (ressourceLocations != null) { +      // load more message sources +      for (final IMessageSourceLocation el : ressourceLocations) { +        if (el.getMessageSourceLocation() != null) { +          for (final String source : el.getMessageSourceLocation()) { +            messageSource.addBasenames(source); +            log.debug("Add additional messageSources: {}", el.getMessageSourceLocation().toArray()); + +          } +        } +      } +    } +      messageSource.setDefaultEncoding("UTF-8");      return messageSource;    }    /** -   * External i18n message source. -   *  +   * Get full message source with internal and external message-properties files. +   * +   * @param ressourceLocations List of source-locations     * @return     */    @Bean -  public ReloadableResourceBundleMessageSource messageSource() { -    final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); +  public ReloadableResourceBundleMessageSource messageSource( +      @Autowired(required = false) final List<IMessageSourceLocation> ressourceLocations) { +    final ReloadableResourceBundleMessageSource messageSource = +        new ReloadableResourceBundleMessageSource();      messageSource.setDefaultEncoding("UTF-8"); -    messageSource.setParentMessageSource(internalMessageSource()); +    messageSource.setParentMessageSource(internalMessageSource(ressourceLocations)); -    final String staticResources = basicConfig.getBasicConfiguration( -        MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_PROPERTIES_PATH); +    final String staticResources = basicConfig +        .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_PROPERTIES_PATH);      try {        if (StringUtils.isNotEmpty(staticResources)) { -        final String absPath = FileUtils.makeAbsoluteUrl(staticResources, basicConfig -            .getConfigurationRootDirectory()); +        final String absPath = +            FileUtils.makeAbsoluteUrl(staticResources, basicConfig.getConfigurationRootDirectory());          messageSource.setBasename(absPath); -        messageSource.setFallbackToSystemLocale(false);        } else {          log.debug("No Ressourcefolder for dynamic Web content templates"); +        }      } catch (final MalformedURLException e) { @@ -137,40 +158,28 @@ public class StaticResourceConfiguration implements WebMvcConfigurer {      return messageSource;    } - +        /** -   * Cookie based i18n language selector. -   *  -   * @return -   */ -  @Bean -  public CookieLocaleResolver localeResolver() { -    final CookieLocaleResolver localeResolver = new CookieLocaleResolver(); -    localeResolver.setCookieName("currentLanguage"); -    localeResolver.setCookieMaxAge(3600); -    return localeResolver; -  } -   -   -  /** -   * Thymeleaf based template resolver. -   *  +   * Get a Tyhmeleaf Template-Resolver with external configuration path. +   *     * @return     */    @Bean(name = "templateResolver")    public FileTemplateResolver templateResolver() { -    final String staticResources = basicConfig.getBasicConfiguration( -        MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_TEMPLATES_PATH); +    final String staticResources = basicConfig +        .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_TEMPLATES_PATH);      try {        if (StringUtils.isNotEmpty(staticResources)) { -        String absPath = FileUtils.makeAbsoluteUrl(staticResources, basicConfig -            .getConfigurationRootDirectory()); +        String absPath = +            FileUtils.makeAbsoluteUrl(staticResources, basicConfig.getConfigurationRootDirectory());          if (!absPath.endsWith("/")) {            absPath += "/"; +          }          if (absPath.startsWith("file:")) {            absPath = absPath.substring("file:".length()); +          }          final FileTemplateResolver viewResolver = new FileTemplateResolver(); @@ -179,11 +188,12 @@ public class StaticResourceConfiguration implements WebMvcConfigurer {          viewResolver.setTemplateMode("HTML");          viewResolver.setCacheable(false); -        log.info("Add Ressourcefolder: " + absPath + " for dynamic Web content templates"); +        log.info("Add Ressourcefolder: {} for dynamic Web content templates", absPath);          return viewResolver;        } else {          log.debug("No Ressourcefolder for dynamic Web content templates"); +        }      } catch (final MalformedURLException e) { @@ -191,8 +201,7 @@ public class StaticResourceConfiguration implements WebMvcConfigurer {      } -    // TODO: implement some backup solution -    return null; +    throw new RuntimeException("Can NOT initialize HTML template resolver");    }  } diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/MonitoringController.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/MonitoringController.java deleted file mode 100644 index f2d9fc8c..00000000 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/MonitoringController.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2018 A-SIT Plus GmbH - * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, - * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "License"); - * You may not use this work except in compliance with the License. - * You may obtain a copy of the License at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. -*/ - -package at.asitplus.eidas.specific.connector.controller; - -import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.transform.TransformerFactoryConfigurationError; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; -import at.gv.egiz.eaaf.core.api.data.EaafConstants; -import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; -import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; -import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; -import at.gv.egiz.eaaf.core.impl.utils.DomUtils; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataConfigurationFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; - -@Controller -public class MonitoringController { -  private static final Logger log = LoggerFactory.getLogger(MonitoringController.class); - -  private static final String MESSAGE_OK = "OK"; -  private static final String MESSAGE_ERROR = "ERROR"; -  private static final String MESSAGE_SKIPPED = "SKIPPED"; - -  private static final String TEST_STORAGE = "Storage: "; -  private static final String TEST_CONFIG = "Config: "; -  private static final String TEST_PVPMETADATA = "PVP_metadata: "; -  private static final String TEST_EIDASNODEMETADATA = "eIDASNode_metadata: "; - -  @Autowired -  private ITransactionStorage storage; -  @Autowired -  private IConfigurationWithSP config; - -  @Autowired private IHttpClientFactory httpClientFactory; -   -  @Autowired -  private PvpMetadataBuilder metadatabuilder; -  @Autowired -  private IPvpMetadataConfigurationFactory configFactory; -  private AbstractCredentialProvider pvpIdpCredentials; - -  /** -   * Sets a specific credential provider for PVP S-Profile IDP component. -   *  -   * @param pvpIdpCredentials credential provider -   */ -  public void setPvpIdpCredentials(AbstractCredentialProvider pvpIdpCredentials) { -    this.pvpIdpCredentials = pvpIdpCredentials; - -  } - -  /** -   * Generic exception handling that wrote an error-message to html response. -   *  -   * @param resp Http response object -   * @param exception Error -   * @throws IOException In case of a html response error. -   */ -  @ExceptionHandler({ Throwable.class }) -  public void genericExceptionHandler(HttpServletResponse resp, Exception exception) throws IOException { -    log.error("Monitoring Servlet receives an error.", exception); -    resp.setContentType(EaafConstants.CONTENTTYPE_HTML_UTF8); -    resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); -    resp.getWriter().write("Reason: " -        + StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(exception.getMessage()))); - -  } - -  /** -   * MS-Connector status-monitoring end-point. -   *  -   * @param req http request -   * @param resp http response -   * @throws IOException In case of a general processing error -   */ -  @RequestMapping(value = { MsEidasNodeConstants.ENDPOINT_MONITORING_MONITOR }, -      method = { RequestMethod.GET }) -  public void startFullTest(HttpServletRequest req, HttpServletResponse resp) throws IOException { -    resp.setContentType(EaafConstants.CONTENTTYPE_HTML_UTF8); - -    try { -      testConfig(); -      testStorage(); -      testPvpMetadata(); -      testEidasNodeMetadata(); -      resp.setStatus(HttpServletResponse.SC_OK); -      resp.getWriter().write(MESSAGE_OK); - -    } catch (final Exception e) { -      resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); -      resp.getWriter().write(MESSAGE_ERROR); - -    } - -  } - -  /** -   * MS-Connector internal verify monitoring end-point. -   *  -   * @param req http request object -   * @param resp http response object -   * @throws IOException In case of an internal processing error -   */ -  @RequestMapping(value = { MsEidasNodeConstants.ENDPOINT_MONITORING_VERIFY }, -      method = { RequestMethod.GET }) - -  public void startSingleTests(HttpServletRequest req, HttpServletResponse resp) throws IOException { -    String result = StringUtils.EMPTY; -    try { -      result += testConfig() + "<br>"; -    } catch (final Exception e) { -      result += e.getMessage() + "<br>"; -    } - -    try { -      result += testStorage() + "<br>"; -    } catch (final Exception e) { -      result += e.getMessage() + "<br>"; -    } - -    try { -      result += testPvpMetadata() + "<br>"; -    } catch (final Exception e) { -      result += e.getMessage() + "<br>"; -    } - -    try { -      result += testEidasNodeMetadata() + "<br>"; -    } catch (final Exception e) { -      result += e.getMessage() + "<br>"; -    } - -    resp.setContentType(EaafConstants.CONTENTTYPE_HTML_UTF8); -    resp.setStatus(HttpServletResponse.SC_OK); -    resp.getWriter().write(result); - -  } - -  private String testStorage() throws Exception { -    try { -      final String key = Random.nextHexRandom16(); -      final String value = Random.nextHexRandom16(); - -      storage.put(key, value, -1); -      final String result = storage.get(key, String.class); -      storage.remove(key); - -      if (result != null && result.equals(value)) { -        return TEST_STORAGE + MESSAGE_OK; -      } else { -        log.warn("Montioring: TestValue: " + value + " does NOT match in Storage test"); -      } - -    } catch (final EaafException e) { -      log.warn("Montioring: Can not read/write to storage.", e); - -    } - -    throw new Exception(TEST_STORAGE + MESSAGE_ERROR); - -  } - -  private String testConfig() throws Exception { -    try { -      if (config.getBasicConfigurationWithPrefix(MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX) != null -          && config.getBasicConfigurationWithPrefix(MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX) -              .size() > 0) { -        return TEST_CONFIG + MESSAGE_OK; -      } else { -        log.warn("Montioring: Can not read from configuration file."); -      } - -    } catch (final Exception e) { -      log.warn("Montioring: Can not read from configuration file.", e); -    } - -    throw new Exception(TEST_CONFIG + MESSAGE_ERROR); - -  } - -  private String testPvpMetadata() throws Exception { -    try { -      // build metadata -      final IPvpMetadataBuilderConfiguration metadataConfig = -          configFactory.generateMetadataBuilderConfiguration( -              "http://localhost/monitoring", -              pvpIdpCredentials); -      metadatabuilder.buildPvpMetadata(metadataConfig); -      return TEST_PVPMETADATA + MESSAGE_OK; - -    } catch (Exception | TransformerFactoryConfigurationError e) { -      log.warn("Monitoring: Has an error in '" + TEST_PVPMETADATA + "': " + e.getMessage(), e); -      throw new Exception(TEST_PVPMETADATA + MESSAGE_ERROR, e); - -    } - -  } - -  private String testEidasNodeMetadata() throws Exception { -    try { -      final String urlString = config.getBasicConfiguration( -          MsEidasNodeConstants.PROP_CONFIG_MONITORING_EIDASNODE_METADATAURL); -      if (StringUtils.isEmpty(urlString)) { -        log.debug("No eIDASNode metadata URL. Skipping test ... "); -        return TEST_EIDASNODEMETADATA + MESSAGE_SKIPPED; - -      } - -      // create HTTP client -      CloseableHttpClient httpClient = httpClientFactory.getHttpClient();       -      URIBuilder uriBuilder = new URIBuilder(urlString);       -      HttpUriRequest request = new HttpGet(uriBuilder.build()); - -      final CloseableHttpResponse respCode = httpClient.execute(request); -      if (respCode.getStatusLine().getStatusCode() != 200) { -        log.warn("Monitoring: Has an error in '" + TEST_EIDASNODEMETADATA + "': " + " HTTP responsecode: " -            + respCode); -        throw new Exception(TEST_EIDASNODEMETADATA + MESSAGE_ERROR); - -      } - -      // parse metadata -      DomUtils.parseXmlNonValidating(respCode.getEntity().getContent()); - -      return TEST_EIDASNODEMETADATA + MESSAGE_OK; - -    } catch (Exception | TransformerFactoryConfigurationError e) { -      log.warn("Monitoring: Has an error in '" + TEST_EIDASNODEMETADATA + "': " + e.getMessage(), e); -      throw new Exception(TEST_EIDASNODEMETADATA + MESSAGE_ERROR, e); - -    } - -  } - -} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/health/EidasNodeMetadataHealthIndicator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/EidasNodeMetadataHealthIndicator.java new file mode 100644 index 00000000..f160916c --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/EidasNodeMetadataHealthIndicator.java @@ -0,0 +1,69 @@ +package at.asitplus.eidas.specific.connector.health; + +import java.io.ByteArrayInputStream; + +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.http.HttpUtils; +import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EidasNodeMetadataHealthIndicator implements HealthIndicator { + +  @Autowired IConfiguration config; +  @Autowired IHttpClientFactory httpClientFactory; +   +  @Override +  public Health health() { +    try { +      final String urlString = config.getBasicConfiguration( +          MsEidasNodeConstants.PROP_CONFIG_MONITORING_EIDASNODE_METADATAURL); +      if (StringUtils.isEmpty(urlString)) { +        log.trace("No eIDASNode metadata URL. Skipping test ... "); +        return Health.unknown().build(); + +      } + +      // create HTTP client +      CloseableHttpClient httpClient = httpClientFactory.getHttpClient();       +      URIBuilder uriBuilder = new URIBuilder(urlString);       +      HttpUriRequest request = new HttpGet(uriBuilder.build()); + +      final Triple<StatusLine, ByteArrayInputStream, ContentType> respCode = httpClient.execute(request, +          HttpUtils.bodyStatusCodeResponseHandler()); +      if (respCode.getFirst().getStatusCode() != 200) { +        log.warn("Monitoring: Get http StatusCode: {} from eIDAS-Node Metadata endpoint",  +            respCode.getFirst().getStatusCode()); +        return Health.down().withDetail("http StatusCode", respCode.getFirst().getStatusCode()).build(); + +      } + +      // parse metadata +      DomUtils.parseXmlNonValidating(respCode.getSecond()); + +      return Health.up().build(); + +    } catch (Exception | TransformerFactoryConfigurationError e) { +      log.warn("Monitoring: Can not read SAML2 metadata from eIDAS-Node", e); +      return Health.down().down(e).build(); + +    } +  } + +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/health/IgniteClusterHealthIndicator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/IgniteClusterHealthIndicator.java new file mode 100644 index 00000000..10517565 --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/IgniteClusterHealthIndicator.java @@ -0,0 +1,52 @@ +package at.asitplus.eidas.specific.connector.health; + +import org.apache.ignite.Ignite; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * HealthCheck that validate Nodes in Apache-Ignite Cluster. + *  + * @author tlenz + * + */ +@Slf4j +public class IgniteClusterHealthIndicator implements HealthIndicator { + +  @Setter +  protected IgniteInstanceInitializerSpecificCommunication igniteInstanceInitializerSpecificCommunication; + +  @Override +  public Health health() { +    final Ignite instance = igniteInstanceInitializerSpecificCommunication.getInstance(); + +    // check if Apache Ignite cluster is active +    if (!instance.cluster().active()) { +      return Health.outOfService().build(); + +    } + +    final Health.Builder healthBuilder; +    // Status UP requires more than 1 node because MS-Connector and eIDAS-Node operations as +    // micro-services +    if (instance.cluster().nodes().size() > 1) { +      healthBuilder = Health.up(); + +    } else { +      // Something looks wrong if only a single node was found because MS-Connector and eIDAS-Node +      // operations as micro-services +      healthBuilder = Health.outOfService(); + +    } + +    healthBuilder.withDetail("#Nodes", instance.cluster().nodes().size()); +    log.trace("Ignite state. #Nodes: {}", instance.cluster().nodes().size()); +    return healthBuilder.build(); + +  } + +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/health/Saml2MetadataHealthIndicator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/Saml2MetadataHealthIndicator.java new file mode 100644 index 00000000..592231b0 --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/health/Saml2MetadataHealthIndicator.java @@ -0,0 +1,44 @@ +package at.asitplus.eidas.specific.connector.health; + +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataConfigurationFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Saml2MetadataHealthIndicator implements HealthIndicator { + +  @Autowired +  private PvpMetadataBuilder metadatabuilder; +  @Autowired +  private IPvpMetadataConfigurationFactory configFactory; +   +  @Setter +  private AbstractCredentialProvider pvpIdpCredentials; +   +  @Override +  public Health health() { +    try { +      // build metadata +      final IPvpMetadataBuilderConfiguration metadataConfig = +          configFactory.generateMetadataBuilderConfiguration( +              "http://localhost/monitoring", +              pvpIdpCredentials); +      metadatabuilder.buildPvpMetadata(metadataConfig); +      return Health.up().build(); + +    } catch (Exception | TransformerFactoryConfigurationError e) { +      return Health.down().down(e).build(); +       +    } +  } + +} diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java index 86808f01..d3b8116a 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/processes/tasks/GenerateCountrySelectionFrameTask.java @@ -26,8 +26,6 @@ package at.asitplus.eidas.specific.connector.processes.tasks;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Component; @@ -39,7 +37,6 @@ import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;  import at.gv.egiz.eaaf.core.api.idp.IConfiguration;  import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;  import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;  import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;  import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; @@ -51,7 +48,6 @@ import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;   */  @Component("GenerateCountrySelectionFrameTask")  public class GenerateCountrySelectionFrameTask extends AbstractAuthServletTask { -  private static final Logger log = LoggerFactory.getLogger(GenerateCountrySelectionFrameTask.class);    @Autowired    ISpringMvcGuiFormBuilder guiBuilder; @@ -77,16 +73,11 @@ public class GenerateCountrySelectionFrameTask extends AbstractAuthServletTask {        guiBuilder.build(request, response, config, "BKU-Selection form"); -    } catch (final GuiBuildException e) { -      log.warn("Can not build GUI:'BKU-Selection'. Msg:" + e.getMessage()); +    } catch (final Exception e) {        throw new TaskExecutionException(pendingReq,            "Can not build GUI. Msg:" + e.getMessage(),            new EaafException("gui.00", new Object[] { e.getMessage() }, e)); -    } catch (final Exception e) { -      log.warn("FinalizeAuthenticationTask has an internal error", e); -      throw new TaskExecutionException(pendingReq, e.getMessage(), e); -      }    } diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/provider/StatusMessageProvider.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/provider/StatusMessageProvider.java index d38da6fe..073f7513 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/provider/StatusMessageProvider.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/provider/StatusMessageProvider.java @@ -94,8 +94,8 @@ public class StatusMessageProvider implements IStatusMessenger {    public String getResponseErrorCode(Throwable throwable) {      String errorCode = IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC;      if (throwable instanceof EaafException) { -      errorCode = ((EaafException) throwable).getErrorId(); - +      errorCode = mapInternalErrorToExternalError(((EaafException) throwable).getErrorId()); +            }      // TODO: maybe more internal switches are required diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/EidasCacheTransactionStoreDecorator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/EidasCacheTransactionStoreDecorator.java index 557e245a..1ea5a280 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/EidasCacheTransactionStoreDecorator.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/EidasCacheTransactionStoreDecorator.java @@ -30,18 +30,47 @@ import java.util.List;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator;  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; +import at.gv.egiz.eaaf.core.impl.utils.Random; -public class EidasCacheTransactionStoreDecorator implements ITransactionStorage { +public class EidasCacheTransactionStoreDecorator implements ITransactionStorage, HealthIndicator {    private static final Logger log = LoggerFactory.getLogger(EidasCacheTransactionStoreDecorator.class);    @Autowired(required = true)    private CacheWithEidasBackend storage;    @Override +  public Health health() { +    try { +      final String key = Random.nextHexRandom16(); +      final String value = Random.nextHexRandom16(); + +      this.put(key, value, -1); +      final String result = this.get(key, String.class); +      this.remove(key); + +      if (result != null && result.equals(value)) { +        return Health.up().build(); +       +      } else { +        log.warn("Montioring: TestValue: " + value + " does NOT match in Storage test"); +        return Health.down().build(); +         +      } + +    } catch (final EaafException e) { +      log.warn("Montioring: Can not read/write to storage.", e); +      return Health.down().down(e).build(); +       +    } +  } +   +  @Override    public void changeKey(String oldKey, String newKey, Object value) throws EaafException {      if (containsKey(oldKey)) {        final TransactionStoreElement el = storage.get(oldKey); @@ -148,5 +177,4 @@ public class EidasCacheTransactionStoreDecorator implements ITransactionStorage      }    } -  } diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java index 26d442cb..3bda2932 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/storage/SimpleInMemoryTransactionStorage.java @@ -33,13 +33,11 @@ import java.util.concurrent.ConcurrentHashMap;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service;  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; -@Service("SimpleInMemoryTransactionStorage")  public class SimpleInMemoryTransactionStorage implements ITransactionStorage {    private static final Logger log = LoggerFactory.getLogger(SimpleInMemoryTransactionStorage.class); diff --git a/connector/src/main/resources/application.properties b/connector/src/main/resources/application.properties new file mode 100644 index 00000000..b13b6c18 --- /dev/null +++ b/connector/src/main/resources/application.properties @@ -0,0 +1,148 @@ +## Set Spring-Boot profile-configuration to 2.3 style +spring.config.use-legacy-processing=true + +## ApplicationServer configuration  +server.servlet.contextPath=/ms_connector +#server.port=7080 + +app.build.artifactId=ms_connector + + +############################################################################# +## SpringBoot Admin client +spring.boot.admin.client.enabled=false + + + + +############################################################################# +## MS-speccific eIDAS-Connector configuration +#proxy.context.url.prefix= +eidas.ms.context.url.request.validation=false +#proxy.configRootDir=file:/.../config/ +eidas.ms.context.use.clustermode=true +eidas.ms.core.logging.level.info.errorcodes=auth.21 + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages +eidas.ms.webcontent.templates.countryselection=countrySelection.html + + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +#eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +#eidas.ms.auth.eIDAS.node_v2.forward.endpoint= +eidas.ms.auth.eIDAS.node_v2.forward.method=POST +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +#eidas.ms.auth.eIDAS.szrclient.useTestService=true +#eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +#eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +#eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +#eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +#eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +#eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false +eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject=false + + +# tech. AuthBlock signing for E-ID process +#eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +#eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +#eidas.ms.auth.eIDAS.authblock.keystore.path=keys/teststore.jks +#eidas.ms.auth.eIDAS.authblock.keystore.type=jks +#eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +#eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=false +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +#eidas.ms.pvp2.keystore.type=jks +#eidas.ms.pvp2.keystore.path=keys/junit.jks +#eidas.ms.pvp2.keystore.password=password +#eidas.ms.pvp2.key.metadata.alias=meta +#eidas.ms.pvp2.key.metadata.password=password +#eidas.ms.pvp2.key.signing.alias=sig +#eidas.ms.pvp2.key.signing.password=password +#eidas.ms.pvp2.metadata.validity=24 + +#eidas.ms.pvp2.metadata.organisation.name=JUnit +#eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +#eidas.ms.pvp2.metadata.organisation.url=http://junit.test +#eidas.ms.pvp2.metadata.contact.givenname=Max +#eidas.ms.pvp2.metadata.contact.surname=Mustermann +#eidas.ms.pvp2.metadata.contact.email=max@junit.test + + +## Service Provider configuration +#eidas.ms.sp.0.uniqueID=https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata +#eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +#eidas.ms.sp.0.pvp2.metadata.truststore.password=password +#eidas.ms.sp.0.friendlyName=jUnit test +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +#eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories=
\ No newline at end of file diff --git a/connector/src/main/resources/applicationContext.xml b/connector/src/main/resources/applicationContext.xml index 76682a2e..15ce0a55 100644 --- a/connector/src/main/resources/applicationContext.xml +++ b/connector/src/main/resources/applicationContext.xml @@ -14,10 +14,14 @@      http://www.springframework.org/schema/tx/spring-tx.xsd">    <context:annotation-config /> -  <mvc:annotation-driven /> +  <context:component-scan base-package="at.gv.egiz.eaaf.utils.springboot.ajp"/> +<!-- +  <context:annotation-config /> +  <mvc:annotation-driven />    <mvc:default-servlet-handler /> - +--> +        <mvc:interceptors>      <bean        class="at.asitplus.eidas.specific.connector.interceptor.WebFrontEndSecurityInterceptor" /> @@ -27,13 +31,24 @@      </bean>    </mvc:interceptors> +  <bean id="springContextClosingHandler" +        class="at.asitplus.eidas.specific.connector.SpringContextCloseHandler" /> + +<!--     <context:property-placeholder      location="${eidas.ms.configuration}" /> +  --> +  <beans profile="deprecatedConfig">    <bean id="BasicMSSpecificNodeConfig"      class="at.asitplus.eidas.specific.connector.config.BasicConfigurationProvider"> -    <constructor-arg -      value="#{systemProperties['eidas.ms.configuration']}" /> +    <constructor-arg value="#{systemProperties['eidas.ms.configuration']}" />    </bean> +  </beans> +  <beans profile="!deprecatedConfig"> +    <bean id="springBootMsSpecificNodeConfig" +          class="at.asitplus.eidas.specific.connector.config.SpringBootBasicConfigurationProvider" /> +           +  </beans>  </beans> diff --git a/connector/src/main/resources/log4j.properties b/connector/src/main/resources/log4j.properties deleted file mode 100644 index 81e54aae..00000000 --- a/connector/src/main/resources/log4j.properties +++ /dev/null @@ -1,55 +0,0 @@ -# commons-logging setup -org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.Log4jFactory - -# define log4j root loggers -log4j.rootLogger=info,stdout, console - -log4j.logger.at.gv.egiz.eaaf=info, msnode -log4j.logger.at.gv.egiz.eidas.specific=info, msnode -log4j.logger.at.gv.egiz.eidas.specific.connector.logger.RevisionLogger=info, reversion -log4j.logger.at.gv.egiz.eidas.specific.connector.logger.StatisticLogger=info, statistic -log4j.logger.eu.eidas=info, EIDASNODE - -log4j.additivity.at.gv.egiz.eidas.specific=false -log4j.additivity.at.gv.egiz.eidas.specific.connector.logger.RevisionLogger=false -log4j.additivity.at.gv.egiz.eidas.specific.connector.logger.StatisticLogger=false -log4j.additivity.eu.eidas=false - -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %20c |  %10t | %m%n - -log4j.appender.stdout=org.apache.log4j.RollingFileAppender -log4j.appender.stdout.File=${catalina.base}/logs/console.log -log4j.appender.stdout.MaxFileSize=10000KB -log4j.appender.stdout.MaxBackupIndex=9999 -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n - -log4j.appender.msnode=org.apache.log4j.RollingFileAppender -log4j.appender.msnode.File=${catalina.base}/logs/eidas-ms-reversion.log -log4j.appender.msnode.MaxFileSize=10000KB -log4j.appender.msnode.MaxBackupIndex=9999 -log4j.appender.msnode.layout=org.apache.log4j.PatternLayout -log4j.appender.msnode.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n - -log4j.appender.reversion=org.apache.log4j.RollingFileAppender -log4j.appender.reversion.File=${catalina.base}/logs/eidas-ms-reversion.log -log4j.appender.reversion.MaxFileSize=10000KB -log4j.appender.reversion.MaxBackupIndex=9999 -log4j.appender.reversion.layout=org.apache.log4j.PatternLayout -log4j.appender.reversion.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n - -log4j.appender.statistic=org.apache.log4j.RollingFileAppender -log4j.appender.statistic.File=${catalina.base}/logs/eidas-ms-statistic.log -log4j.appender.statistic.MaxFileSize=10000KB -log4j.appender.statistic.MaxBackupIndex=9999 -log4j.appender.statistic.layout=org.apache.log4j.PatternLayout -log4j.appender.statistic.layout.ConversionPattern=%m%n - -log4j.appender.EIDASNODE=org.apache.log4j.RollingFileAppender -log4j.appender.EIDASNODE.File=${catalina.base}/logs/eIDAS_node.log -log4j.appender.EIDASNODE.MaxFileSize=10000KB -log4j.appender.EIDASNODE.MaxBackupIndex=9999 -log4j.appender.EIDASNODE.layout=org.apache.log4j.PatternLayout -log4j.appender.EIDASNODE.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n
\ No newline at end of file diff --git a/connector/src/main/resources/logback.xml b/connector/src/main/resources/logback.xml index a0a9995e..7aa2d0cc 100644 --- a/connector/src/main/resources/logback.xml +++ b/connector/src/main/resources/logback.xml @@ -11,14 +11,14 @@    <appender name="msnode"      class="ch.qos.logback.core.rolling.RollingFileAppender">      <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender --> -    <File>${catalina.base}/logs/eidas-ms-reversion.log</File> +    <File>logs/eidas-ms-specific.log</File>      <encoder>        <pattern>%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n</pattern>      </encoder>      <rollingPolicy        class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">        <maxIndex>9999</maxIndex> -      <FileNamePattern>${catalina.base}/logs/eidas-ms-reversion.log.%i +      <FileNamePattern>logs/eidas-ms-specific.log.%i        </FileNamePattern>      </rollingPolicy>      <triggeringPolicy @@ -29,14 +29,14 @@    <appender name="EIDASNODE"      class="ch.qos.logback.core.rolling.RollingFileAppender">      <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender --> -    <File>${catalina.base}/logs/eIDAS_node.log</File> +    <File>logs/eIDAS_node.log</File>      <encoder>        <pattern>%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n</pattern>      </encoder>      <rollingPolicy        class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">        <maxIndex>9999</maxIndex> -      <FileNamePattern>${catalina.base}/logs/eIDAS_node.log.%i +      <FileNamePattern>logs/eIDAS_node.log.%i        </FileNamePattern>      </rollingPolicy>      <triggeringPolicy @@ -47,14 +47,14 @@    <appender name="reversion"      class="ch.qos.logback.core.rolling.RollingFileAppender">      <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender --> -    <File>${catalina.base}/logs/eidas-ms-reversion.log</File> +    <File>logs/eidas-ms-reversion.log</File>      <encoder>        <pattern>%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n</pattern>      </encoder>      <rollingPolicy        class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">        <maxIndex>9999</maxIndex> -      <FileNamePattern>${catalina.base}/logs/eidas-ms-reversion.log.%i +      <FileNamePattern>logs/eidas-ms-reversion.log.%i        </FileNamePattern>      </rollingPolicy>      <triggeringPolicy @@ -65,14 +65,14 @@    <appender name="statistic"      class="ch.qos.logback.core.rolling.RollingFileAppender">      <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender --> -    <File>${catalina.base}/logs/eidas-ms-statistic.log</File> +    <File>logs/eidas-ms-statistic.log</File>      <encoder>        <pattern>%m%n</pattern>      </encoder>      <rollingPolicy        class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">        <maxIndex>9999</maxIndex> -      <FileNamePattern>${catalina.base}/logs/eidas-ms-statistic.log.%i +      <FileNamePattern>logs/eidas-ms-statistic.log.%i        </FileNamePattern>      </rollingPolicy>      <triggeringPolicy @@ -83,14 +83,14 @@    <appender name="stdout"      class="ch.qos.logback.core.rolling.RollingFileAppender">      <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender --> -    <File>${catalina.base}/logs/console.log</File> +    <File>logs/console.log</File>      <encoder>        <pattern>%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n</pattern>      </encoder>      <rollingPolicy        class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">        <maxIndex>9999</maxIndex> -      <FileNamePattern>${catalina.base}/logs/console.log.%i +      <FileNamePattern>logs/console.log.%i        </FileNamePattern>      </rollingPolicy>      <triggeringPolicy diff --git a/connector/src/main/resources/specific_eIDAS_connector.beans.xml b/connector/src/main/resources/specific_eIDAS_connector.beans.xml index 5cf0d5b8..f6fdeefe 100644 --- a/connector/src/main/resources/specific_eIDAS_connector.beans.xml +++ b/connector/src/main/resources/specific_eIDAS_connector.beans.xml @@ -11,23 +11,24 @@      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"> -  <context:annotation-config /> -  <mvc:annotation-driven /> -  <mvc:default-servlet-handler /> +  <import resource="common_gui.beans.xml"/>    <bean id="WebResourceConfiguration"      class="at.asitplus.eidas.specific.connector.config.StaticResourceConfiguration" /> -  <bean id="ProcessEngineSignalController" +  <bean id="processEngineSignalController"      class="at.asitplus.eidas.specific.connector.controller.ProcessEngineSignalController" /> -  <bean id="MonitoringController" -    class="at.asitplus.eidas.specific.connector.controller.MonitoringController"> +  <bean id="saml2MetadataGeneration" +        class="at.asitplus.eidas.specific.connector.health.Saml2MetadataHealthIndicator">      <property name="pvpIdpCredentials">        <ref bean="PVPEndPointCredentialProvider" />      </property>    </bean> +  <bean id="eidasNodeMetadata" +        class="at.asitplus.eidas.specific.connector.health.EidasNodeMetadataHealthIndicator" /> +    <bean id="AuthenticationManager"      class="at.asitplus.eidas.specific.connector.auth.AuthenticationManager" /> @@ -43,7 +44,7 @@    <bean id="PVPMetadataConfigurationFactory"      class="at.asitplus.eidas.specific.connector.provider.PvpMetadataConfigurationFactory" /> -  <bean id="PVP2XProtocol" +  <bean id="pvp2SProfileEndpoint"      class="at.asitplus.eidas.specific.connector.controller.Pvp2SProfileEndpoint">      <property name="pvpIdpCredentials">        <ref bean="PVPEndPointCredentialProvider" /> @@ -96,17 +97,6 @@    <bean id="mvcGUIBuilderImpl"      class="at.asitplus.eidas.specific.connector.gui.SpringMvcGuiFormBuilderImpl" /> -  <bean id="templateEngine" -    class="org.thymeleaf.spring5.SpringTemplateEngine"> -    <property name="templateResolver" ref="templateResolver" /> -  </bean> - -  <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> -    <property name="order" value="2" /> -    <property name="templateEngine" ref="templateEngine" /> -    <property name="characterEncoding" value="UTF-8" /> -  </bean> -    <bean id="StatusMessageProvider"      class="at.asitplus.eidas.specific.connector.provider.StatusMessageProvider" /> diff --git a/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml b/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml index 08c7b672..2e4d1742 100644 --- a/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml +++ b/connector/src/main/resources/specific_eIDAS_connector.storage.beans.xml @@ -27,12 +27,15 @@    <bean id="msNodeCacheImpl"      class="eu.eidas.auth.cache.ConcurrentCacheServiceIgniteSpecificCommunicationImpl"> -    <property -      name="igniteInstanceInitializerSpecificCommunication" -      ref="eidasIgniteInstanceInitializerSpecificCommunication" /> +    <property name="igniteInstanceInitializerSpecificCommunication" ref="eidasIgniteInstanceInitializerSpecificCommunication" />      <property name="cacheName" value="msConnectorCache" />    </bean> +  <bean id="IgniteClusterState" +        class="at.asitplus.eidas.specific.connector.health.IgniteClusterHealthIndicator"> +    <property name="igniteInstanceInitializerSpecificCommunication" ref="eidasIgniteInstanceInitializerSpecificCommunication" />         +  </bean> +    <!-- bean id="defaultHazelcastInstance" class="java.lang.String"> <constructor-arg       value="eidasHazelcastInstance"/> </bean> <bean id="eidasHazelcastInstanceInitializer"  diff --git a/connector/src/main/resources/tomcat.properties b/connector/src/main/resources/tomcat.properties new file mode 100644 index 00000000..38ab5a64 --- /dev/null +++ b/connector/src/main/resources/tomcat.properties @@ -0,0 +1,15 @@ +tomcat.ajp.enabled=true +#tomcat.ajp.port=41009 +#tomcat.ajp.additionalAttributes.secretrequired=true +#tomcat.ajp.additionalAttributes.secret= + +server.tomcat.accesslog.buffered=false +server.tomcat.accesslog.prefix=tomcat-access_log +server.tomcat.accesslog.directory=logs/ +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.file-date-format=.yyyy-MM-dd +server.tomcat.accesslog.pattern=common +server.tomcat.accesslog.rename-on-rotate=false +server.tomcat.accesslog.request-attributes-enabled=true +server.tomcat.accesslog.rotate=true +server.tomcat.accesslog.suffix=.log
\ No newline at end of file diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/FullStartUpAndProcessTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/FullStartUpAndProcessTest.java new file mode 100644 index 00000000..77037415 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/FullStartUpAndProcessTest.java @@ -0,0 +1,485 @@ +package at.asitplus.eidas.specific.connector.test; + +import static org.mockito.ArgumentMatchers.any; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.util.Map; +import java.util.Timer; + +import javax.xml.transform.TransformerException; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.ignite.Ignition; +import org.joda.time.DateTime; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.config.InitializationException; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.StatusResponseType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.core.io.ResourceLoader; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.Base64Utils; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.skjolberg.mockito.soap.SoapServiceRule; + +import at.asitplus.eidas.specific.connector.controller.ProcessEngineSignalController; +import at.asitplus.eidas.specific.connector.controller.Pvp2SProfileEndpoint; +import at.asitplus.eidas.specific.connector.provider.PvpEndPointCredentialProvider; +import at.asitplus.eidas.specific.connector.provider.PvpMetadataProvider; +import at.asitplus.eidas.specific.connector.test.saml2.Pvp2SProfileEndPointTest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasSignalServlet; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.gv.egiz.components.spring.api.SpringBootApplicationContextInitializer; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.controller.ProtocolFinalizationController; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; +import lombok.val; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.xml.XMLParserException; +import szrservices.SZR; +import szrservices.SignContentEntry; +import szrservices.SignContentResponseType; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@ContextConfiguration(initializers = { +    org.springframework.boot.context.config.DelegatingApplicationContextInitializer.class, +    SpringBootApplicationContextInitializer.class    +    }) +@TestPropertySource(locations = { "file:src/test/resources/config/junit_config_1_springboot.properties" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +@ActiveProfiles(profiles = {"JUNIT", "jUnitTestMode"}) +public class FullStartUpAndProcessTest { + +  private static final String FINAL_REDIRECT = "http://localhost/finalizeAuthProtocol?pendingid="; +   +  @Autowired private WebApplicationContext wac; +  @Autowired private PvpEndPointCredentialProvider credentialProvider; +  @Autowired private PvpMetadataProvider metadataProvider; +  @Autowired private ResourceLoader resourceLoader; +  @Autowired private EidasAttributeRegistry attrRegistry; +   +  @Autowired private Pvp2SProfileEndpoint sProfile; +  @Autowired private ProcessEngineSignalController signal; +  @Autowired private EidasSignalServlet eidasSignal; +  @Autowired private ProtocolFinalizationController finalize; +   +  @Rule +  public final SoapServiceRule soap = SoapServiceRule.newInstance(); +   +  private SZR szrMock; +   +  private String cc; +  private String givenName; +  private String familyName; +  private String dateOfBirth; +  private String personalId; +  private String vsz; +  private String eidasBind; +   +   +  /** +   * jUnit class initializer. +   * @throws InterruptedException In case of an error +   * @throws ComponentInitializationException  In case of an error +   * @throws InitializationException In case of an error +   * +   */ +  @BeforeClass +  public static void classInitializer() throws InterruptedException, InitializationException, ComponentInitializationException { +    final String current = new java.io.File(".").toURI().toString(); +    System.clearProperty("eidas.ms.configuration"); +     +    //eIDAS Ref. Impl. properties +    System.setProperty("EIDAS_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_CONNECTOR_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_PROXY_SERVICE_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +         +    EaafOpenSaml3xInitializer.eaafInitialize(); +     +  } +   +  /** +   * Test shut-down. +   * +   * @throws IOException In case of an error +   */ +  @AfterClass +  public static void closeIgniteNode() throws IOException { +    System.out.println("Closiong Ignite Node ... "); +    Ignition.stopAll(true); + +  } + +  /** +   * jUnit test set-up. +   * +   * +   */ +  @Before +  public void setup() throws IOException { +    DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac); +    @SuppressWarnings("rawtypes") +    Map<String, FilterRegistrationBean> filters = wac.getBeansOfType(FilterRegistrationBean.class); +    for (FilterRegistrationBean<?> filter : filters.values()) { +      if (filter.isEnabled()) { +        builder.addFilter(filter.getFilter(), "/*"); +       +      } +    } + +    szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); +     +     +     +    cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); +    personalId = cc + "/AT/" + RandomStringUtils.randomNumeric(64); +    familyName = RandomStringUtils.randomAlphabetic(10); +    givenName = RandomStringUtils.randomAlphabetic(10); +    dateOfBirth = "2015-10-12"; +     +    vsz = RandomStringUtils.randomNumeric(10); +    eidasBind = RandomStringUtils.randomAlphanumeric(50); +     +  } +   +  @Test +  public void userStopProcess() throws UnsupportedEncodingException, XMLParserException, UnmarshallingException,  +      TransformerException, IOException, MarshallingException, ComponentInitializationException, EaafException { +    //start authentication process by sending a SAML2 Authn-Request +    MockHttpServletRequest saml2Req = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    injectSaml2AuthnReq(saml2Req); +    MockHttpServletResponse selectCountryResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(saml2Req, selectCountryResp)); +     +    // send SAML2 AuthnRequest  +    sProfile.pvpIdpPostRequest(saml2Req, selectCountryResp); +     +    //check country-selection response +    Assert.assertEquals("no country-selection page", 200, selectCountryResp.getStatus()); +    Assert.assertEquals("cc-selection page", "text/html;charset=UTF-8", selectCountryResp.getContentType()); +    String selectionPage = selectCountryResp.getContentAsString(); +    Assert.assertNotNull("selectionPage is null", selectionPage); +    Assert.assertFalse("selectionPage is empty", selectionPage.isEmpty()); +     +    String pendingReqId = extractRequestToken(selectionPage,  +        "<input  type=\"hidden\" name=\"pendingid\"  value=\""); +    Assert.assertFalse("PendingReqId", pendingReqId.isEmpty()); +     +     +    // set-up user-stop request +    MockHttpServletRequest userStopReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    userStopReq.setParameter("pendingid", pendingReqId); +    userStopReq.setParameter(EaafConstants.PARAM_HTTP_STOP_PROCESS, "true"); +     +    MockHttpServletResponse finalizeResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(userStopReq, finalizeResp)); +     +    // send user-stop request +    signal.performGenericAuthenticationProcess(userStopReq, finalizeResp); +     +    //validate state +    Assert.assertEquals("forward to finalization", 302, finalizeResp.getStatus()); +    Assert.assertNotNull("missing redirect header", finalizeResp.getHeader("Location")); +    Assert.assertTrue("wrong redirect header", finalizeResp.getHeader("Location").startsWith(FINAL_REDIRECT)); +    String finalPendingReqId = finalizeResp.getHeader("Location").substring(FINAL_REDIRECT.length()); +    Assert.assertFalse("final pendingRequestId", finalPendingReqId.isEmpty()); +     +    //set-up finalization request +    MockHttpServletRequest finalizationReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    finalizationReq.setParameter("pendingid", finalPendingReqId); +     +    MockHttpServletResponse saml2Resp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(finalizationReq, saml2Resp)); +     +    // exexcute finalization step +    finalize.finalizeAuthProtocol(finalizationReq, saml2Resp); +     +    //validate state +    Assert.assertEquals("forward to finalization", 200, saml2Resp.getStatus()); +    Assert.assertEquals("forward to eIDAS Node page", "text/html;charset=UTF-8", saml2Resp.getContentType()); +    String saml2RespPage = saml2Resp.getContentAsString(); +    Assert.assertNotNull("selectionPage is null", saml2RespPage); +    Assert.assertFalse("selectionPage is empty", saml2RespPage.isEmpty()); +     +    //validate SAML2 response +    String saml2RespB64 = extractRequestToken(saml2RespPage,  +        "<input type=\"hidden\" name=\"SAMLResponse\" value=\""); +    Assert.assertNotNull("SAML2 response", saml2RespB64); +     +    StatusResponseType saml2 = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( +        XMLObjectProviderRegistrySupport.getParserPool(),  +        new ByteArrayInputStream(Base64Utils.decodeFromString(saml2RespB64))); +    Assert.assertEquals("SAML2 status", "urn:oasis:names:tc:SAML:2.0:status:Responder",  +        saml2.getStatus().getStatusCode().getValue()); +    Assert.assertEquals("ms-connector status", "1005",  +        saml2.getStatus().getStatusCode().getStatusCode().getValue()); +     +  } +   +  @Test +  public void fullSuccessProcess() throws EaafException, Exception { +    //start authentication process by sending a SAML2 Authn-Request +    MockHttpServletRequest saml2Req = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    injectSaml2AuthnReq(saml2Req); +    MockHttpServletResponse selectCountryResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(saml2Req, selectCountryResp)); +     +    // send SAML2 AuthnRequest  +    sProfile.pvpIdpPostRequest(saml2Req, selectCountryResp); +     +    //check country-selection response +    Assert.assertEquals("no country-selection page", 200, selectCountryResp.getStatus()); +    Assert.assertEquals("cc-selection page", "text/html;charset=UTF-8", selectCountryResp.getContentType()); +    String selectionPage = selectCountryResp.getContentAsString(); +    Assert.assertNotNull("selectionPage is null", selectionPage); +    Assert.assertFalse("selectionPage is empty", selectionPage.isEmpty()); +     +    String pendingReqId = extractRequestToken(selectionPage,  +        "<input  type=\"hidden\" name=\"pendingid\"  value=\""); +    Assert.assertFalse("PendingReqId", pendingReqId.isEmpty()); +     +     +    // set-up country-selection request +    MockHttpServletRequest selectCountryReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    selectCountryReq.setParameter("pendingid", pendingReqId); +    selectCountryReq.setParameter("selectedCountry", cc); +     +    MockHttpServletResponse forwardEidasNodeResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(selectCountryReq, forwardEidasNodeResp)); +     +    // send country-selection request +    signal.performGenericAuthenticationProcess(selectCountryReq, forwardEidasNodeResp); +     +    //check forward to eIDAS node response +    Assert.assertEquals("forward to eIDAS Node", 200, forwardEidasNodeResp.getStatus()); +    Assert.assertEquals("forward to eIDAS Node page", "text/html;charset=UTF-8", forwardEidasNodeResp.getContentType()); +    String forwardPage = forwardEidasNodeResp.getContentAsString(); +    Assert.assertNotNull("forward to eIDAS Node is null", forwardPage); +    Assert.assertFalse("forward to eIDAS Node is empty", forwardPage.isEmpty()); +     +    String eidasNodeReqToken = extractRequestToken(forwardPage,  +        "<input type=\"hidden\" name=\"token\" value=\""); +    Assert.assertFalse("eidas req. token", eidasNodeReqToken.isEmpty()); +     +    //check eIDAS node request and build respose +    String eidasRespToken = validateEidasNodeRequestAndBuildResponse(eidasNodeReqToken); +    Assert.assertFalse("eidas resp. token", eidasRespToken.isEmpty()); +     +     +    // set-up eIDAS-node response +    MockHttpServletRequest eidasNodeRespReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    eidasNodeRespReq.setParameter("token", eidasRespToken); +     +    MockHttpServletResponse finalizeResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(eidasNodeRespReq, finalizeResp)); +     +    injectSzrResponse(); +     +    //excute eIDAS node response +    eidasSignal.restoreEidasAuthProcess(eidasNodeRespReq, finalizeResp); +     +    //validate state +    Assert.assertEquals("forward to finalization", 302, finalizeResp.getStatus()); +    Assert.assertNotNull("missing redirect header", finalizeResp.getHeader("Location")); +    Assert.assertTrue("wrong redirect header", finalizeResp.getHeader("Location").startsWith(FINAL_REDIRECT)); +    String finalPendingReqId = finalizeResp.getHeader("Location").substring(FINAL_REDIRECT.length()); +    Assert.assertFalse("final pendingRequestId", finalPendingReqId.isEmpty()); +     +     +    //set-up finalization request +    MockHttpServletRequest finalizationReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); +    finalizationReq.setParameter("pendingid", finalPendingReqId); +     +    MockHttpServletResponse saml2Resp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(finalizationReq, saml2Resp)); +     +    // exexcute finalization step +    finalize.finalizeAuthProtocol(finalizationReq, saml2Resp); +     +    //validate state +    Assert.assertEquals("forward to finalization", 200, saml2Resp.getStatus()); +    Assert.assertEquals("forward to eIDAS Node page", "text/html;charset=UTF-8", saml2Resp.getContentType()); +    String saml2RespPage = saml2Resp.getContentAsString(); +    Assert.assertNotNull("selectionPage is null", saml2RespPage); +    Assert.assertFalse("selectionPage is empty", saml2RespPage.isEmpty()); +     +    //validate SAML2 response +    String saml2RespB64 = extractRequestToken(saml2RespPage,  +        "<input type=\"hidden\" name=\"SAMLResponse\" value=\""); +    Assert.assertNotNull("SAML2 response", saml2RespB64); +     +    StatusResponseType saml2 = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( +        XMLObjectProviderRegistrySupport.getParserPool(),  +        new ByteArrayInputStream(Base64Utils.decodeFromString(saml2RespB64))); +    Assert.assertEquals("SAML2 status", Constants.SUCCESS_URI, saml2.getStatus().getStatusCode().getValue()); +     +    final AssertionAttributeExtractor extractor = new AssertionAttributeExtractor(saml2); +    Assert.assertEquals("wrong resp attr. size", 6, extractor.getAllIncludeAttributeNames().size()); +    Assert.assertEquals("Wrong attr: LoA ", "http://eidas.europa.eu/LoA/high",  +        extractor.getSingleAttributeValue("urn:oid:1.2.40.0.10.2.1.1.261.108")); +    Assert.assertEquals("Wrong attr: PVP_VERSION ", "2.2",  +        extractor.getSingleAttributeValue("urn:oid:1.2.40.0.10.2.1.1.261.10")); +    Assert.assertEquals("Wrong attr: EID_ISSUER_NATION  ", cc,  +        extractor.getSingleAttributeValue("urn:oid:1.2.40.0.10.2.1.1.261.32")); +    Assert.assertEquals("Wrong attr: eidasBind", eidasBind,  +        extractor.getSingleAttributeValue("urn:eidgvat:attributes.eidbind")); +    Assert.assertNotNull("Wrong attr:  authBlock",  +        extractor.getSingleAttributeValue("urn:eidgvat:attributes.authblock.signed")); +    Assert.assertNotNull("Wrong attr: piiTras.Id ",  +        extractor.getSingleAttributeValue("urn:eidgvat:attributes.piiTransactionId")); +     +  } + +  private void injectSzrResponse() throws Exception { +     +    when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(vsz); +    val signContentResp = new SignContentResponseType(); +    final SignContentEntry signContentEntry = new SignContentEntry(); +    signContentEntry.setValue(eidasBind); +    signContentResp.getOut().add(signContentEntry); +    when(szrMock, "signContent", any(), any(), any()).thenReturn(signContentResp); +     +  } + +  private String validateEidasNodeRequestAndBuildResponse(String eidasNodeReqToken)  +      throws SpecificCommunicationException, URISyntaxException { +    final SpecificCommunicationService springManagedSpecificConnectorCommunicationService = +        (SpecificCommunicationService) wac.getBean( +            SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString()); +     +    //read request and validate basic properties  +    ILightRequest req = springManagedSpecificConnectorCommunicationService.getAndRemoveRequest(eidasNodeReqToken,  +        attrRegistry.getCoreAttributeRegistry().getAttributes()); +     +    Assert.assertNotNull("eIDAS Node req", req); +    Assert.assertEquals("Wrong CC", cc, req.getCitizenCountryCode()); +    Assert.assertEquals("Wrong CC", EaafConstants.EIDAS_LOA_HIGH, req.getLevelOfAssurance()); +     +     +    //set response from eIDAS node +    BinaryLightToken respoToken = springManagedSpecificConnectorCommunicationService.putResponse( +        buildDummyAuthResponse(Constants.SUCCESS_URI, req.getId())); +    return Base64Utils.encodeToString(respoToken.getTokenBytes()); +     +  } + +  private AuthenticationResponse buildDummyAuthResponse(String statusCode, String reqId) throws URISyntaxException { +    final AttributeDefinition<?> attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); +    final AttributeDefinition<?> attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); +    final AttributeDefinition<?> attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); +    final AttributeDefinition<?> attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        Constants.eIDAS_ATTR_DATEOFBIRTH).first(); +    +    final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() +        .put(attributeDef, personalId) +        .put(attributeDef2, familyName) +        .put(attributeDef3, givenName) +        .put(attributeDef4, dateOfBirth).build(); + +    val b = new AuthenticationResponse.Builder(); +    return b.id("_".concat(Random.nextHexRandom16())) +        .issuer(RandomStringUtils.randomAlphabetic(10)) +        .subject(RandomStringUtils.randomAlphabetic(10)) +        .statusCode(statusCode) +        .inResponseTo(reqId) +        .subjectNameIdFormat("afaf") +        .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) +        .attributes(attributeMap) +        .build(); +     +  } +   +  private String extractRequestToken(String selectionPage, String selector) { +    int start = selectionPage.indexOf(selector); +    Assert.assertTrue("find no pendingReqId location start", start > 0); +    int end = selectionPage.indexOf("\"", start + selector.length()); +    Assert.assertTrue("find no pendingReqId location end", end > 0); +    return selectionPage.substring(start + selector.length(), end); +     +  } + +  private void injectSaml2AuthnReq(MockHttpServletRequest saml2Req) throws XMLParserException, UnmarshallingException,  +      SamlSigningException, CredentialsNotAvailableException, UnsupportedEncodingException, TransformerException,  +      IOException, MarshallingException, ComponentInitializationException { +    final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( +        XMLObjectProviderRegistrySupport.getParserPool(), +        Pvp2SProfileEndPointTest.class.getResourceAsStream("/data/pvp2_authn_1.xml")); +    authnReq.setIssueInstant(DateTime.now());     +    RequestAbstractType signedAuthnReq =  +        Saml2Utils.signSamlObject(authnReq, credentialProvider.getMessageSigningCredential(), true);            +    String b64 = Base64Utils.encodeToString(DomUtils.serializeNode( +          XMLObjectSupport.getMarshaller(signedAuthnReq).marshall(signedAuthnReq)).getBytes("UTF-8"));     +    saml2Req.setParameter("SAMLRequest", b64); +             +    final org.springframework.core.io.Resource resource = resourceLoader.getResource( +        "classpath:/data/metadata_valid_without_encryption.xml"); +    Timer timer = new Timer("PVP metadata-resolver refresh"); +    ResourceBackedMetadataResolver fileSystemResolver =  +        new ResourceBackedMetadataResolver(timer, new OpenSaml3ResourceAdapter(resource)); +    fileSystemResolver.setId("test"); +    fileSystemResolver.setParserPool(XMLObjectProviderRegistrySupport.getParserPool()); +    fileSystemResolver.initialize();                     +    metadataProvider.addMetadataResolverIntoChain(fileSystemResolver); +     +  } +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassExecutableModeTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassExecutableModeTest.java new file mode 100644 index 00000000..86df55df --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassExecutableModeTest.java @@ -0,0 +1,113 @@ +package at.asitplus.eidas.specific.connector.test; + +import java.io.IOException; +import java.lang.reflect.Field; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.ignite.Ignition; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.asitplus.eidas.specific.connector.SpringBootApplicationInitializer; +import at.gv.egiz.eaaf.core.impl.logging.DummyStatusMessager; +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RunWith(BlockJUnit4ClassRunner.class) +public class MainClassExecutableModeTest { + +  /** +   * jUnit class initializer. +   * @throws InterruptedException In case of an error +   * +   */ +  @BeforeClass +  public static void classInitializer() throws InterruptedException { +    final String current = new java.io.File(".").toURI().toString(); +    System.clearProperty("eidas.ms.configuration"); +     +    //eIDAS Ref. Impl. properties +    System.setProperty("EIDAS_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_CONNECTOR_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_PROXY_SERVICE_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +         +  } + +  /** +   * Initializer. +   * @throws InterruptedException In case of an error  +   * +   */ +  @AfterClass +  public static void closeIgniteNode() throws InterruptedException { +    System.out.println("Closing Ignite Node ... "); +     +    log.info("Stopping already running Apache Ignite nodes ... "); +    Ignition.stopAll(true);     +    Thread.sleep(1000); +     +  } +   +  /** +   * Test reseter. +   * +   */ +  @After +  public void cleanJvmState() throws NoSuchFieldException, SecurityException, +      IllegalArgumentException, IllegalAccessException { +    final Field field = LogMessageProviderFactory.class.getDeclaredField("internalMessager"); +    field.setAccessible(true); +    field.set(null, new DummyStatusMessager()); +     +    System.clearProperty("eidas.ms.configuration"); +    SpringBootApplicationInitializer.exit(); +     +  } +   +    +  @Test +  public void validConfigLocation() throws Throwable { +    SpringBootApplicationInitializer +        .main(new String[] { +            "--spring.config.location=src/test/resources/config/junit_config_2_springboot.properties,classpath:/application.properties", +            "--spring.profiles.active=jUnitTestMode" }); + +    System.out.println("Is started!"); + +    // test Spring-Actuator http Basic-Auth +    testSpringActuatorSecurity(); + +  } + +  private void testSpringActuatorSecurity() throws ClientProtocolException, IOException { +    // check if authentication works on actuator end-point +    final HttpClientBuilder builder = HttpClients.custom(); +    final CloseableHttpClient client = builder.build(); +    Assert.assertNotNull("httpClient", client); + +    final HttpUriRequest httpGetInfo = new HttpGet("http://localhost:8080/ms_connector/actuator/info"); +    final CloseableHttpResponse httpRespInfo = client.execute(httpGetInfo); +    Assert.assertEquals("http statusCode", 200, httpRespInfo.getStatusLine().getStatusCode()); +     +    final HttpUriRequest httpGetHealth = new HttpGet("http://localhost:8080/ms_connector/actuator/health"); +    final CloseableHttpResponse httpRespHealth = client.execute(httpGetHealth); +    Assert.assertEquals("http statusCode", 503, httpRespHealth.getStatusLine().getStatusCode()); +     +  } + +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassWebAppModeTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassWebAppModeTest.java new file mode 100644 index 00000000..07ef4968 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassWebAppModeTest.java @@ -0,0 +1,134 @@ +package at.asitplus.eidas.specific.connector.test; + +import java.io.IOException; +import java.lang.reflect.Field; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.ignite.Ignition; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.asitplus.eidas.specific.connector.SpringBootApplicationInitializer; +import at.gv.egiz.eaaf.core.impl.logging.DummyStatusMessager; +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; + +@RunWith(BlockJUnit4ClassRunner.class) +public class MainClassWebAppModeTest { + +  /** +   * jUnit class initializer. +   * +   */ +  @BeforeClass +  public static void classInitializer() { +    final String current = new java.io.File(".").toURI().toString(); +     +    //eIDAS Ref. Impl. properties +    System.setProperty("EIDAS_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_CONNECTOR_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +    System.setProperty("SPECIFIC_PROXY_SERVICE_CONFIG_REPOSITORY", current.substring("file:".length()) +        + "../basicConfig/eIDAS/"); +     +  } + +  /** +   * Initializer. +   * +   */ +  @AfterClass +  public static void closeIgniteNode() { +    System.out.println("Closing Ignite Node ... "); +    Ignition.stopAll(true); +     +  } +   +  /** +   * Test reseter. +   * +   */ +  @After +  public void cleanJvmState() throws NoSuchFieldException, SecurityException, +      IllegalArgumentException, IllegalAccessException { +    final Field field = LogMessageProviderFactory.class.getDeclaredField("internalMessager"); +    field.setAccessible(true); +    field.set(null, new DummyStatusMessager()); + +    System.clearProperty("eidas.ms.configuration"); +    SpringBootApplicationInitializer.exit(); +        +  } +   +  @Test +  public void wrongConfigLocation() throws Throwable { +    //MS-specific connector property +    final String current = new java.io.File(".").toURI().toString(); +    System.setProperty("eidas.ms.configuration", current +        + "src/test/resources/config/notextist.properties"); +     +    try { +    //starting application +      SpringBootApplicationInitializer +          .main(new String[] { +              "--spring.profiles.active=jUnitTestMode" }); +      Assert.fail("Missing configuration not detected"); + +    } catch (final Exception e) { +      Assert.assertNotNull("Exception is null", e);       + +    } +  } +   +   +  @Test +  public void systemdConfigLocation() throws Throwable {     +    //MS-specific connector property +    final String current = new java.io.File(".").toURI().toString(); +    System.setProperty("eidas.ms.configuration", current +        + "src/test/resources/config/junit_config_1_springboot.properties"); +         +    //starting application +    SpringBootApplicationInitializer +        .main(new String[] { +            "--spring.profiles.active=jUnitTestMode,springBoot" }); + +    System.out.println("Is started!"); + +    // test Spring-Actuator http Basic-Auth +    testSpringActuatorSecurity(); + +     +     +     +  } +   +  private void testSpringActuatorSecurity() throws ClientProtocolException, IOException { +    // check if authentication works on actuator end-point +    final HttpClientBuilder builder = HttpClients.custom(); +    final CloseableHttpClient client = builder.build(); +    Assert.assertNotNull("httpClient", client); + +    final HttpUriRequest httpGetInfo = new HttpGet("http://localhost:8080/ms_connector/actuator/info"); +    final CloseableHttpResponse httpRespInfo = client.execute(httpGetInfo); +    Assert.assertEquals("http statusCode", 200, httpRespInfo.getStatusLine().getStatusCode()); + +     +    final HttpUriRequest httpGetHealth = new HttpGet("http://localhost:8080/ms_connector/actuator/health"); +    final CloseableHttpResponse httpRespHealth = client.execute(httpGetHealth); +    Assert.assertEquals("http statusCode", 503, httpRespHealth.getStatusLine().getStatusCode()); +     +  } + +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/attributes/AuthBlockAttributeBuilderTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/attributes/AuthBlockAttributeBuilderTest.java index f6d22c98..5c0a1420 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/attributes/AuthBlockAttributeBuilderTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/attributes/AuthBlockAttributeBuilderTest.java @@ -2,6 +2,8 @@ package at.asitplus.eidas.specific.connector.test.attributes;  import static at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.EID_AUTHBLOCK_SIGNED_NAME; +import java.util.Base64; +  import org.junit.Assert;  import org.junit.Before;  import org.junit.Rule; @@ -64,7 +66,8 @@ public class AuthBlockAttributeBuilderTest extends AbstractAttributeBuilderTest        final String value = attrBuilde.build(spConfig, authData, gen); -      Assert.assertEquals("Authblock build wrong", JSW, value); +      Assert.assertNotNull("AuthBlock", value); +      Assert.assertEquals("Authblock build wrong", JSW, new String(Base64.getDecoder().decode(value)));      } catch (final Exception e) {        Assert.assertNull("Attr. builder has an exception", e); diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/BasicConfigurationTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/config/BasicConfigurationTest.java index 6e52f113..80307ea2 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/BasicConfigurationTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/config/BasicConfigurationTest.java @@ -1,4 +1,4 @@ -package at.asitplus.eidas.specific.connector.test; +package at.asitplus.eidas.specific.connector.test.config;  import java.net.MalformedURLException;  import java.net.URL; @@ -12,6 +12,7 @@ import org.opensaml.core.config.InitializationException;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.test.annotation.DirtiesContext;  import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -34,6 +35,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx      "/spring/SpringTest-context_simple_storage.xml" })  @WebAppConfiguration  @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +@ActiveProfiles(profiles = {"deprecatedConfig"})  public class BasicConfigurationTest {    @Autowired private IConfigurationWithSP basicConfig; diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/controller/ProcessEngineSignalControllerTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/controller/ProcessEngineSignalControllerTest.java new file mode 100644 index 00000000..d2c4aff2 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/controller/ProcessEngineSignalControllerTest.java @@ -0,0 +1,77 @@ +package at.asitplus.eidas.specific.connector.test.controller; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.connector.controller.ProcessEngineSignalController; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ +    "/applicationContext.xml", +    "/specific_eIDAS_connector.beans.xml", +    "/eaaf_core.beans.xml", +    "/eaaf_pvp.beans.xml", +    "/eaaf_pvp_idp.beans.xml", +    "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"}) +@WebAppConfiguration +public class ProcessEngineSignalControllerTest { + +  @Autowired private ProcessEngineSignalController controller; +   +  private MockHttpServletRequest httpReq; +  private MockHttpServletResponse httpResp; +   +  @BeforeClass +  public static void classInitializer() { +    final String current = new java.io.File(".").toURI().toString(); +    System.setProperty("eidas.ms.configuration", current + "src/test/resources/config/junit_config_1.properties"); +     +  } +   +  /** +   * jUnit test set-up. +   */ +  @Before +  public void setUp() throws EaafStorageException, URISyntaxException { +    httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); +    httpResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); +      +  } +   +  @Test +  public void noPendingRequestId() throws IOException, EaafException { +  //set-up +     +    //execute test +    controller.performGenericAuthenticationProcess(httpReq, httpResp); +        +    //validate state +    Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); +    Assert.assertNotNull("redirect header", httpResp.getHeaderValue("Location")); +    Assert.assertTrue("wrong redirect header",  +        httpResp.getHeader("Location").startsWith("http://localhost/errorHandling?errorid=")); +   +  } +   +   +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java new file mode 100644 index 00000000..b04a5bdb --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java @@ -0,0 +1,70 @@ +package at.asitplus.eidas.specific.connector.test.health; + +import java.io.IOException; + +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import at.asitplus.eidas.specific.connector.health.EidasNodeMetadataHealthIndicator; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ +    "/spring/SpringTest-context_healthcheck.xml" }) +@TestPropertySource(locations = {"classpath:/config/junit_config_2_springboot.properties"}) +@WebAppConfiguration +public class EidasNodeMetadataHealthIndicatorNoEndpointTest { +  +  @Autowired EidasNodeMetadataHealthIndicator health; +   +  private static MockWebServer mockWebServer = null; +  +  /** +   * Testclass initializer. +   * +   * @throws IOException In case of an error +   */ +  @BeforeClass +  public static void classInitializer() throws IOException { +    mockWebServer = new MockWebServer(); +    mockWebServer.start(40900); +    mockWebServer.url("/mockup"); + +  } + +  @AfterClass +  public static void resetTestEnviroment() throws NoSuchFieldException, SecurityException, +      IllegalArgumentException, IllegalAccessException, IOException { +    mockWebServer.shutdown(); + +  } +     +  @Test +  public void noEndpointInConfiguration() throws IOException { +    //set-up status +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorNoEndpointTest.class +            .getResourceAsStream("/config/log4j.properties"), "UTF-8")) +        .setHeader("Content-Type", MediaType.APPLICATION_XML)); + +    //perform test +    Health status = health.health(); +     +    //validate state +    Assert.assertEquals("wrong healthState", Health.unknown().build().getStatus(), status.getStatus()); +     +  } +   +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorTest.java new file mode 100644 index 00000000..b044d4d2 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/health/EidasNodeMetadataHealthIndicatorTest.java @@ -0,0 +1,102 @@ +package at.asitplus.eidas.specific.connector.test.health; + +import java.io.IOException; + +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import at.asitplus.eidas.specific.connector.health.EidasNodeMetadataHealthIndicator; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ +    "/spring/SpringTest-context_healthcheck.xml" }) +@TestPropertySource(locations = {"classpath:/config/junit_config_1_springboot.properties"}) +@WebAppConfiguration +public class EidasNodeMetadataHealthIndicatorTest { +  +  @Autowired EidasNodeMetadataHealthIndicator health; +   +  private static MockWebServer mockWebServer = null; +  +  /** +   * Testclass initializer. +   * +   * @throws IOException In case of an error +   */ +  @BeforeClass +  public static void classInitializer() throws IOException { +    mockWebServer = new MockWebServer(); +    mockWebServer.start(40900); +    mockWebServer.url("/mockup"); + +  } + +  @AfterClass +  public static void resetTestEnviroment() throws NoSuchFieldException, SecurityException, +      IllegalArgumentException, IllegalAccessException, IOException { +    mockWebServer.shutdown(); + +  } +   +  @Test +  public void httpStatusCode500() throws IOException { +    //set-up status +    mockWebServer.enqueue(new MockResponse().setResponseCode(500) +        .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class +            .getResourceAsStream("/data/metadata_valid.xml"), "UTF-8")) +        .setHeader("Content-Type", MediaType.APPLICATION_XML)); + +    //perform test +    Health status = health.health(); +     +    //validate state +    Assert.assertEquals("wrong healthState", Health.down().build().getStatus(), status.getStatus()); +     +  }  + +  @Test +  public void httpStatusCode200() throws IOException { +    //set-up status +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class +            .getResourceAsStream("/data/metadata_valid.xml"), "UTF-8")) +        .setHeader("Content-Type", MediaType.APPLICATION_XML)); + +    //perform test +    Health status = health.health(); +     +    //validate state +    Assert.assertEquals("wrong healthState", Health.up().build().getStatus(), status.getStatus()); +     +  } +   +  @Test +  public void noXmlResponse() throws IOException { +    //set-up status +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class +            .getResourceAsStream("/config/log4j.properties"), "UTF-8")) +        .setHeader("Content-Type", MediaType.APPLICATION_XML)); + +    //perform test +    Health status = health.health(); +     +    //validate state +    Assert.assertEquals("wrong healthState", Health.down().build().getStatus(), status.getStatus()); +     +  } +   +} diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/saml2/Pvp2SProfileEndPointTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/saml2/Pvp2SProfileEndPointTest.java index 81ee2625..bcba3e11 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/saml2/Pvp2SProfileEndPointTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/saml2/Pvp2SProfileEndPointTest.java @@ -39,6 +39,7 @@ import org.springframework.mock.web.MockHttpServletRequest;  import org.springframework.mock.web.MockHttpServletResponse;  import org.springframework.test.annotation.DirtiesContext;  import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -68,6 +69,7 @@ import net.shibboleth.utilities.java.support.xml.XMLParserException;      "/eaaf_pvp.beans.xml",      "/eaaf_pvp_idp.beans.xml",      "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"})  @WebAppConfiguration  @DirtiesContext(classMode = ClassMode.BEFORE_CLASS)  public class Pvp2SProfileEndPointTest { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/EvaluateCountrySelectionTaskTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/EvaluateCountrySelectionTaskTest.java index 9d590055..4bff9416 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/EvaluateCountrySelectionTaskTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/EvaluateCountrySelectionTaskTest.java @@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.context.i18n.LocaleContextHolder;  import org.springframework.mock.web.MockHttpServletRequest;  import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -34,6 +35,7 @@ import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl;      "/eaaf_pvp.beans.xml",      "/eaaf_pvp_idp.beans.xml",      "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"})  @WebAppConfiguration  public class EvaluateCountrySelectionTaskTest { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/GenerateCountrySelectionFrameTaskTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/GenerateCountrySelectionFrameTaskTest.java index 2a1d7cd4..d902f758 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/GenerateCountrySelectionFrameTaskTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/task/GenerateCountrySelectionFrameTaskTest.java @@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.context.i18n.LocaleContextHolder;  import org.springframework.mock.web.MockHttpServletRequest;  import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -32,6 +33,7 @@ import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl;      "/eaaf_pvp.beans.xml",      "/eaaf_pvp_idp.beans.xml",      "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"})  @WebAppConfiguration  public class GenerateCountrySelectionFrameTaskTest { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthenticationDataBuilderTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java index 316dcb5f..5f1c5dcf 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthenticationDataBuilderTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java @@ -1,4 +1,4 @@ -package at.asitplus.eidas.specific.connector.test; +package at.asitplus.eidas.specific.connector.test.utils;  import static at.asitplus.eidas.specific.connector.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.context.i18n.LocaleContextHolder;  import org.springframework.mock.web.MockHttpServletRequest;  import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -50,8 +51,9 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xIniti  import net.shibboleth.utilities.java.support.component.ComponentInitializationException;  @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration({ "/applicationContext.xml", "/SpringTest_connector.beans.xml", "/eaaf_core.beans.xml", +@ContextConfiguration({ "/applicationContext.xml", "/spring/SpringTest_connector.beans.xml", "/eaaf_core.beans.xml",      "/eaaf_pvp.beans.xml", "/eaaf_pvp_idp.beans.xml", "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"})  @WebAppConfiguration  public class AuthenticationDataBuilderTest { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java index 389f561e..9aafb4b6 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java @@ -1,4 +1,4 @@ -package at.asitplus.eidas.specific.connector.test; +package at.asitplus.eidas.specific.connector.test.utils;  import java.io.IOException;  import java.util.HashMap; @@ -22,6 +22,7 @@ import org.springframework.mock.web.MockHttpServletRequest;  import org.springframework.mock.web.MockHttpServletResponse;  import org.springframework.test.annotation.DirtiesContext;  import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ActiveProfiles;  import org.springframework.test.context.ContextConfiguration;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.springframework.test.context.web.WebAppConfiguration; @@ -52,6 +53,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx      "/eaaf_pvp.beans.xml",      "/eaaf_pvp_idp.beans.xml",      "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"})  @WebAppConfiguration  @DirtiesContext(classMode = ClassMode.BEFORE_CLASS)  public class AuthnRequestValidatorTest { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/CountrySelectionProcessImplTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/CountrySelectionProcessImplTest.java index 455288f5..d0343eba 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/CountrySelectionProcessImplTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/CountrySelectionProcessImplTest.java @@ -1,4 +1,4 @@ -package at.asitplus.eidas.specific.connector.test; +package at.asitplus.eidas.specific.connector.test.utils;  import java.util.HashMap;  import java.util.Map; diff --git a/connector/src/test/resources/config/junit_config_1.properties b/connector/src/test/resources/config/junit_config_1.properties index 78981b6a..f6b3e4c1 100644 --- a/connector/src/test/resources/config/junit_config_1.properties +++ b/connector/src/test/resources/config/junit_config_1.properties @@ -1,6 +1,7 @@  ## Basic service configuration  eidas.ms.context.url.prefix=http://localhost  eidas.ms.context.url.request.validation=false +eidas.ms.core.configRootDir=file:./src/test/resources/config/  eidas.ms.context.use.clustermode=true diff --git a/connector/src/test/resources/config/junit_config_1_springboot.properties b/connector/src/test/resources/config/junit_config_1_springboot.properties new file mode 100644 index 00000000..e63cda7b --- /dev/null +++ b/connector/src/test/resources/config/junit_config_1_springboot.properties @@ -0,0 +1,83 @@ +## embbeded Tomcat +tomcat.workingdir=./target/work +tomcat.ajp.enabled=true +tomcat.ajp.port=8009 +tomcat.ajp.networkAddress=127.0.0.1 +tomcat.ajp.additionalAttributes.secretrequired=true +tomcat.ajp.additionalAttributes.secret=junit + +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url=http://localhost:40900/mockup + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://eidas.node/junit + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= + +#tech. AuthBlock signing for E-ID process +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=keys/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.type=jks +eidas.ms.pvp2.keystore.path=keys/junit.jks +eidas.ms.pvp2.keystore.password=password +eidas.ms.pvp2.key.metadata.alias=meta +eidas.ms.pvp2.key.metadata.password=password +eidas.ms.pvp2.key.signing.alias=sig +eidas.ms.pvp2.key.signing.password=password +eidas.ms.pvp2.metadata.validity=24 + +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test + +## Service Provider configuration +eidas.ms.sp.0.uniqueID=https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata +eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.0.pvp2.metadata.truststore.password=password +eidas.ms.sp.0.friendlyName=jUnit test +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + +## Service Provider configuration +eidas.ms.sp.1.uniqueID=https://demo.egiz.gv.at/junit_test +eidas.ms.sp.1.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.1.pvp2.metadata.truststore.password=password +eidas.ms.sp.1.friendlyName=jUnit test +eidas.ms.sp.1.pvp2.metadata.url=http://junit.test/metadata +eidas.ms.sp.1.policy.allowed.requested.targets=test +eidas.ms.sp.1.policy.hasBaseIdTransferRestriction=true + diff --git a/connector/src/test/resources/config/junit_config_2_springboot.properties b/connector/src/test/resources/config/junit_config_2_springboot.properties new file mode 100644 index 00000000..ecb22dec --- /dev/null +++ b/connector/src/test/resources/config/junit_config_2_springboot.properties @@ -0,0 +1,83 @@ +## embbeded Tomcat +tomcat.workingdir=./target/work +tomcat.ajp.enabled=true +tomcat.ajp.port=8009 +tomcat.ajp.networkAddress=127.0.0.1 +tomcat.ajp.additionalAttributes.secretrequired=true +tomcat.ajp.additionalAttributes.secret=junit + +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://eidas.node/junit + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= + +#tech. AuthBlock signing for E-ID process +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=keys/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.type=jks +eidas.ms.pvp2.keystore.path=keys/junit.jks +eidas.ms.pvp2.keystore.password=password +eidas.ms.pvp2.key.metadata.alias=meta +eidas.ms.pvp2.key.metadata.password=password +eidas.ms.pvp2.key.signing.alias=sig +eidas.ms.pvp2.key.signing.password=password +eidas.ms.pvp2.metadata.validity=24 + +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test + +## Service Provider configuration +eidas.ms.sp.0.uniqueID=https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata +eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.0.pvp2.metadata.truststore.password=password +eidas.ms.sp.0.friendlyName=jUnit test +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + +## Service Provider configuration +eidas.ms.sp.1.uniqueID=https://demo.egiz.gv.at/junit_test +eidas.ms.sp.1.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.1.pvp2.metadata.truststore.password=password +eidas.ms.sp.1.friendlyName=jUnit test +eidas.ms.sp.1.pvp2.metadata.url=http://junit.test/metadata +eidas.ms.sp.1.policy.allowed.requested.targets=test +eidas.ms.sp.1.policy.hasBaseIdTransferRestriction=true + diff --git a/connector/src/test/resources/config/junit_config_3.properties b/connector/src/test/resources/config/junit_config_3.properties index 32e30790..8b2c63a8 100644 --- a/connector/src/test/resources/config/junit_config_3.properties +++ b/connector/src/test/resources/config/junit_config_3.properties @@ -1,6 +1,7 @@  ## Basic service configuration  eidas.ms.context.url.prefix=  eidas.ms.context.url.request.validation=false +eidas.ms.core.configRootDir=file:./src/test/resources/config/  eidas.ms.context.use.clustermode=true diff --git a/connector/src/test/resources/config/keys/teststore.jks b/connector/src/test/resources/config/keys/teststore.jksBinary files differ new file mode 100644 index 00000000..fcc6400c --- /dev/null +++ b/connector/src/test/resources/config/keys/teststore.jks diff --git a/connector/src/test/resources/config/templates/error_message.html b/connector/src/test/resources/config/templates/error_message.html index da423592..86f9d29d 100644 --- a/connector/src/test/resources/config/templates/error_message.html +++ b/connector/src/test/resources/config/templates/error_message.html @@ -21,8 +21,8 @@                <div id="alert_area" class="hell" role="application" >                  <p th:text="#{gui.errorpage.msg.information}">Error Information</p>                    <br/> -		              <p><b th:text="#{gui.errorpage.msg.errorcode}">Code :</b> <span th:text="${msg.errorCode}"></span></p>  -                  <p><b th:text="#{gui.errorpage.msg.errormsg}">Msg   :</b > <span th:text="${#messages.msgWithParams('__${msg.errorCode}__', '__${msg.errorParams}__')}"></span></p> +		              <p><b th:text="#{gui.errorpage.msg.errorcode}">Code :</b> <span th:text="${errorCode}"></span></p>  +                  <p><b th:text="#{gui.errorpage.msg.errormsg}">Msg   :</b > <span th:text="${#messages.msgWithParams('__${errorCode}__', '__${errorParams}__')}"></span></p>  	            </div>	                                                                                                        <!-- errorMsg -->	  	        </div>	 diff --git a/connector/src/test/resources/data/metadata_valid_without_encryption.xml b/connector/src/test/resources/data/metadata_valid_without_encryption.xml new file mode 100644 index 00000000..b224c336 --- /dev/null +++ b/connector/src/test/resources/data/metadata_valid_without_encryption.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_b67c160c0ad7b4ebd430581df167ac23" entityID="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata"> +  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> +    <ds:SignedInfo> +      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> +      <ds:Reference URI="#_b67c160c0ad7b4ebd430581df167ac23"> +        <ds:Transforms> +          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +        </ds:Transforms> +        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> +        <ds:DigestValue>00SaL0XjeknOb/DttutP50lTyAux1jaRPJIVdSupWvU=</ds:DigestValue> +      </ds:Reference> +    </ds:SignedInfo> +    <ds:SignatureValue>PfEBmLMX/ZgL6ViXghyWtal5MaMoW8k3zjw+54+WK1OAtVsVgOsIDRJE0M/a/VXBbMSifgY6J1gN23xhr61jkrjRQEkbDzLpWZLzWAJ65YqqUQo8wsKI2Gz0j12yY5D8/GOamKOH9KDi5ba1veXR/fnxRINoy7nZo4tcUWZChdl8BWkMN5ugr6dORNIQg/Ym3GabQ/hR5z+9FmveAKphdH63MC6qW3EgM9EMvOVkrLBTP92sNMAAJeaawui9tlxi9anVQ0OqwZsgKLvI7fyV4CM/0sd/ELjeReIlWlHk07Nz4eltMq3eOx3q1YurYvhE8XapHiQMehOtCS+Fzh10sw==</ds:SignatureValue> +    <ds:KeyInfo> +      <ds:X509Data> +        <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> +      </ds:X509Data> +    </ds:KeyInfo> +  </ds:Signature> +  <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> +    <md:KeyDescriptor use="signing"> +      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> +        <ds:X509Data> +          <ds:X509Certificate>MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +HhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwC +LZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqG +SM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIh +ANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L</ds:X509Certificate> +        </ds:X509Data> +      </ds:KeyInfo> +    </md:KeyDescriptor> +    <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> +    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/post" index="0" isDefault="true"/> +    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/redirect" index="1"/> +    <md:AttributeConsumingService index="0" isDefault="true"> +      <md:ServiceName xml:lang="en">Default Service</md:ServiceName> +      <md:RequestedAttribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> +      <md:RequestedAttribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> +      <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="MANDATE-TYPE-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.106" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="EID-IDENTITY-LINK" Name="urn:oid:1.2.40.0.10.2.1.1.261.38" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="EID-CITIZEN-QAA-EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> +      <md:RequestedAttribute FriendlyName="userAuthBlock" Name="urn:eidgvat:attributes.authblock.signed" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="eidBind" Name="urn:eidgvat:attributes.eidbind" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +      <md:RequestedAttribute FriendlyName="piiTransactionId" Name="urn:eidgvat:attributes.piiTransactionId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> +    </md:AttributeConsumingService> +  </md:SPSSODescriptor> +  <md:Organization> +    <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> +    <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> +    <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> +  </md:Organization> +  <md:ContactPerson contactType="technical"> +    <md:Company>E-Government Innovationszentrum</md:Company> +    <md:GivenName>Lenz</md:GivenName> +    <md:SurName>Thomas</md:SurName> +    <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> +    <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> +  </md:ContactPerson> +</md:EntityDescriptor> diff --git a/connector/src/test/resources/spring/SpringTest-context_healthcheck.xml b/connector/src/test/resources/spring/SpringTest-context_healthcheck.xml new file mode 100644 index 00000000..3bac88e3 --- /dev/null +++ b/connector/src/test/resources/spring/SpringTest-context_healthcheck.xml @@ -0,0 +1,22 @@ +<?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" +  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"> + +  <context:annotation-config /> + +  <import resource="classpath:/SpringTest-context_authManager.xml" /> + +  <bean id="basicConfig" +        class="at.asitplus.eidas.specific.connector.config.SpringBootBasicConfigurationProvider" /> + +  <bean id="eidasNodeMetadata" +        class="at.asitplus.eidas.specific.connector.health.EidasNodeMetadataHealthIndicator" /> + +</beans>
\ No newline at end of file diff --git a/connector/src/main/resources/SpringTest_connector.beans.xml b/connector/src/test/resources/spring/SpringTest_connector.beans.xml index 5cf0d5b8..ba385cb9 100644 --- a/connector/src/main/resources/SpringTest_connector.beans.xml +++ b/connector/src/test/resources/spring/SpringTest_connector.beans.xml @@ -21,13 +21,6 @@    <bean id="ProcessEngineSignalController"      class="at.asitplus.eidas.specific.connector.controller.ProcessEngineSignalController" /> -  <bean id="MonitoringController" -    class="at.asitplus.eidas.specific.connector.controller.MonitoringController"> -    <property name="pvpIdpCredentials"> -      <ref bean="PVPEndPointCredentialProvider" /> -    </property> -  </bean> -    <bean id="AuthenticationManager"      class="at.asitplus.eidas.specific.connector.auth.AuthenticationManager" /> | 
