diff options
34 files changed, 1462 insertions, 190 deletions
| diff --git a/basicConfig/default_config.properties b/basicConfig/default_config.properties index fabfdfef..d6cc1317 100644 --- a/basicConfig/default_config.properties +++ b/basicConfig/default_config.properties @@ -66,8 +66,8 @@ 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=true -eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=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 diff --git a/connector/checks/spotbugs-exclude.xml b/connector/checks/spotbugs-exclude.xml index 5d4fd515..281e3796 100644 --- a/connector/checks/spotbugs-exclude.xml +++ b/connector/checks/spotbugs-exclude.xml @@ -19,4 +19,9 @@        </OR>        <Bug pattern="SPRING_CSRF_UNRESTRICTED_REQUEST_MAPPING" />                     </Match> +    <Match> +      <!-- Path to application configuration is trusted --> +      <Class name="at.asitplus.eidas.specific.connector.MsSpecificSpringBootApplicationContextInitializer" /> +      <Bug pattern="PATH_TRAVERSAL_IN" /> +    </Match>  </FindBugsFilter> diff --git a/connector/pom.xml b/connector/pom.xml index dad27b38..7fbc2a36 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -49,7 +49,15 @@        <artifactId>authmodule-eIDAS-v2</artifactId>      </dependency> -    <!-- Third party libs --> +    <!-- Third party libs -->        +    <dependency> +      <groupId>org.springframework.boot</groupId> +      <artifactId>spring-boot-starter-actuator</artifactId> +    </dependency> +    <dependency> +      <groupId>de.codecentric</groupId> +      <artifactId>spring-boot-admin-starter-client</artifactId> +    </dependency>      <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-webmvc</artifactId> @@ -74,11 +82,10 @@        <groupId>org.apache.commons</groupId>        <artifactId>commons-collections4</artifactId>      </dependency> -    <dependency> -      <groupId>javax.servlet</groupId> -      <artifactId>javax.servlet-api</artifactId> -      <scope>provided</scope> -    </dependency> +   <dependency> +        <groupId>org.hibernate.validator</groupId> +        <artifactId>hibernate-validator</artifactId> +    </dependency>          <!-- Testing --> @@ -104,8 +111,63 @@        <scope>test</scope>        <type>test-jar</type>      </dependency> +    <dependency> +      <groupId>org.springframework.boot</groupId> +      <artifactId>spring-boot-starter-tomcat</artifactId> +      <scope>test</scope> +    </dependency> +    <dependency> +      <groupId>at.gv.egiz.eaaf</groupId> +      <artifactId>eaaf-springboot-utils</artifactId> +      <scope>test</scope> +    </dependency>         </dependencies> +   +  <profiles> +    <profile> +     <id>default</id> +      <activation> +        <activeByDefault>true</activeByDefault> +        <property> +          <name>default</name> +        </property> +      </activation> +      <dependencies> +        <dependency> +          <groupId>org.springframework.boot</groupId> +          <artifactId>spring-boot-starter-web</artifactId> +          <exclusions> +            <exclusion> +              <groupId>org.springframework.boot</groupId> +              <artifactId>spring-boot-starter-tomcat</artifactId> +            </exclusion> +          </exclusions> +        </dependency>  +         +        <dependency> +          <groupId>javax.servlet</groupId> +          <artifactId>javax.servlet-api</artifactId> +          <scope>provided</scope> +        </dependency> +      </dependencies> +    </profile> +    <profile> +     <id>embbededTomcat</id> +      <dependencies> +        <dependency> +          <groupId>org.springframework.boot</groupId> +          <artifactId>spring-boot-starter-web</artifactId> +        </dependency>  +        <dependency> +          <groupId>at.gv.egiz.eaaf</groupId> +          <artifactId>eaaf-springboot-utils</artifactId> +        </dependency>         +      </dependencies> +    </profile> +     +  </profiles> +      <build>      <finalName>ms_connector</finalName> @@ -126,6 +188,24 @@        </plugin>        <plugin> +        <groupId>org.springframework.boot</groupId> +        <artifactId>spring-boot-maven-plugin</artifactId> +        <version>2.2.6.RELEASE</version> +        <configuration> +          <executable>true</executable> +          <!-- layout>ZIP</layout --> +        </configuration> +        <executions> +          <execution> +            <goals> +              <goal>build-info</goal> +              <goal>repackage</goal> +            </goals> +          </execution> +        </executions> +      </plugin> + +      <plugin>          <groupId>org.apache.maven.plugins</groupId>          <artifactId>maven-assembly-plugin</artifactId>          <configuration> 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..5160bdf5 --- /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..0d3226bf --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringBootApplicationInitializer.java @@ -0,0 +1,60 @@ +package at.asitplus.eidas.specific.connector; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; +import at.gv.egiz.eaaf.core.impl.logging.SimpleStatusMessager; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SpringBootApplication(scanBasePackages = {"at.gv.egiz.eaaf.utils.springboot.ajp"}) +public class SpringBootApplicationInitializer { + +  private static ConfigurableApplicationContext ctx; + +  /** +   * Starts MS-specific eIDAS-Implementation SpringBoot application. +   * +   * @param args Starting parameters +   */ +  public static void main(final String[] args) { +    try { +      log.info("=============== Initializing Spring-Boot context! ==============="); +      LogMessageProviderFactory.setStatusMessager(new SimpleStatusMessager()); +      final SpringApplication springApp = +          new SpringApplication(SpringBootApplicationInitializer.class); +      springApp.addInitializers(new MsSpecificSpringBootApplicationContextInitializer()); + +      log.debug("Run SpringBoot initialization process ... "); +      ctx = springApp.run(args); + +      log.info("Initialization of MS-specific eIDAS-Implementation finished."); + +    } catch (final Throwable e) { +      log.error("MS-specific eIDAS-Implementation initialization FAILED!", e); +      throw e; + +    } + +  } + +  /** +   * 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..2a3b659a --- /dev/null +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/SpringContextCloseHandler.java @@ -0,0 +1,224 @@ +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()) { +      // Not needed yet +      // int retryCount = 0; +      // while(executor.getActiveCount()>0 && ++retryCount<51){ +      // try { +      // log.debug("Executer {} is still working with active {} work. Retry count is +      // {}", +      // executor.getThreadNamePrefix(), +      // executor.getActiveCount(), +      // retryCount); +      // Thread.sleep(1000); +      // +      // } catch (final InterruptedException e) { +      // e.printStackTrace(); +      // } +      // } +      // +      // if(!(retryCount<51)) +      // log.debug("Executer {} is still working. Since Retry count exceeded max value +      // {}, will be +      // killed immediately", +      // executor.getThreadNamePrefix(), +      // retryCount); + +      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()); + +    // for (final ThreadPoolTaskScheduler scheduler : schedulers.values()) { +    // scheduler.getScheduledExecutor().shutdown(); +    // try { +    // scheduler.getScheduledExecutor().awaitTermination(20000, +    // TimeUnit.MILLISECONDS); +    // if(scheduler.getScheduledExecutor().isTerminated() || +    // scheduler.getScheduledExecutor().isShutdown()) +    // log.debug("Scheduler {} has stoped", scheduler.getThreadNamePrefix()); +    // +    // else{ +    // log.debug("Scheduler {} has not stoped normally and will be shut down +    // immediately", +    // scheduler.getThreadNamePrefix()); +    // scheduler.getScheduledExecutor().shutdownNow(); +    // log.info("Scheduler {} has shut down immediately", +    // scheduler.getThreadNamePrefix()); +    // +    // } +    // +    // } catch (final IllegalStateException e) { +    // e.printStackTrace(); +    // +    // } catch (final InterruptedException e) { +    // e.printStackTrace(); +    // +    // } finally { +    // scheduler.shutdown(); +    // +    // } +    // } + +  } + +  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/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/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..2cb0c83a --- /dev/null +++ b/connector/src/main/resources/application.properties @@ -0,0 +1,144 @@ +## 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 + + +##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/substantial + +#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 + + +# 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..8a21e68f 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="!springBoot">    <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="springBoot"> +    <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..aa5040fa 100644 --- a/connector/src/main/resources/specific_eIDAS_connector.beans.xml +++ b/connector/src/main/resources/specific_eIDAS_connector.beans.xml @@ -11,17 +11,15 @@      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" +  <bean id="monitoringController"      class="at.asitplus.eidas.specific.connector.controller.MonitoringController">      <property name="pvpIdpCredentials">        <ref bean="PVPEndPointCredentialProvider" /> @@ -43,7 +41,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 +94,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/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/MainClassExecutableModeTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassExecutableModeTest.java new file mode 100644 index 00000000..66147971 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassExecutableModeTest.java @@ -0,0 +1,109 @@ +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 ClientProtocolException, IOException { +    SpringBootApplicationInitializer +        .main(new String[] { +            "--spring.config.location=src/test/resources/config/junit_config_1_springboot.properties,classpath:/application.properties", +            "--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 httpGet1 = new HttpGet("http://localhost:8080/ms_connector/actuator/info"); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1); +    Assert.assertEquals("http statusCode", 200, httpResp1.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..265edfb6 --- /dev/null +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/MainClassWebAppModeTest.java @@ -0,0 +1,129 @@ +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() { +    //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,springBoot" }); +      Assert.fail("Missing configuration not detected"); + +    } catch (final Exception e) { +      Assert.assertNotNull("Exception is null", e);       + +    } +  } +   +   +  @Test +  public void systemdConfigLocation() throws ClientProtocolException, IOException {     +    //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 httpGet1 = new HttpGet("http://localhost:8080/ms_connector/actuator/info"); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1); +    Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode()); + +  } + +} 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..86342f99 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; 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..87abb06f 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; 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..a9929a01 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; 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..429d3538 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:./  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..7257df9b --- /dev/null +++ b/connector/src/test/resources/config/junit_config_1_springboot.properties @@ -0,0 +1,81 @@ +## 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= + +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=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 + +## 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/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_lib/pom.xml b/connector_lib/pom.xml index b6a2e060..f24a2801 100644 --- a/connector_lib/pom.xml +++ b/connector_lib/pom.xml @@ -27,6 +27,10 @@        <groupId>org.springframework</groupId>        <artifactId>spring-webmvc</artifactId>      </dependency> +    <dependency> +      <groupId>javax.validation</groupId> +      <artifactId>validation-api</artifactId> +    </dependency>      <dependency>        <groupId>javax.servlet</groupId> @@ -44,20 +48,20 @@        <groupId>org.springframework</groupId>        <artifactId>spring-test</artifactId>        <scope>test</scope> -    </dependency>     +    </dependency>      <dependency>        <groupId>at.gv.egiz.eaaf</groupId>        <artifactId>eaaf_core_utils</artifactId>        <scope>test</scope>        <type>test-jar</type> -    </dependency>     +    </dependency>      <dependency> -        <groupId>at.gv.egiz.eaaf</groupId> -        <artifactId>eaaf-core</artifactId> -        <scope>test</scope> -        <type>test-jar</type> -    </dependency>  -     +      <groupId>at.gv.egiz.eaaf</groupId> +      <artifactId>eaaf-core</artifactId> +      <scope>test</scope> +      <type>test-jar</type> +    </dependency> +    </dependencies>    <build> @@ -87,7 +91,7 @@            </dependency>          </dependencies>        </plugin> -       +        <plugin>          <groupId>com.github.spotbugs</groupId>          <artifactId>spotbugs-maven-plugin</artifactId> diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java index 8d1dcc0b..133f104d 100644 --- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java @@ -103,7 +103,7 @@ public class MsEidasNodeConstants { -  public static final String PROP_CONFIG_SP_LIST_PREFIX = "sp."; +  public static final String PROP_CONFIG_SP_LIST_PREFIX = "sp";    public static final String PROP_CONFIG_SP_UNIQUEIDENTIFIER = EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER;    public static final String PROP_CONFIG_SP_FRIENDLYNAME = "friendlyName";    public static final String PROP_CONFIG_SP_PVP2_METADATA_URL = "pvp2.metadata.url"; diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/BasicConfigurationProvider.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/BasicConfigurationProvider.java index 355c63f2..8f15a12d 100644 --- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/BasicConfigurationProvider.java +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/BasicConfigurationProvider.java @@ -31,6 +31,7 @@ import java.util.Map.Entry;  import org.apache.commons.lang3.StringUtils;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile;  import org.springframework.stereotype.Service;  import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; @@ -41,6 +42,7 @@ import at.gv.egiz.eaaf.core.impl.idp.conf.AbstractConfigurationImpl;  import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;  @Service("BasicMSSpecificNodeConfig") +@Profile("!springBoot")  public class BasicConfigurationProvider extends AbstractConfigurationImpl {    private static final Logger log = LoggerFactory.getLogger(BasicConfigurationProvider.class); @@ -56,7 +58,7 @@ public class BasicConfigurationProvider extends AbstractConfigurationImpl {      if (!spConfigCache.containsKey(entityId)) {        log.debug("SP: " + entityId + " is NOT cached. Starting load operation ...  ");        final Map<String, String> allSPs = getBasicConfigurationWithPrefix( -          MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX); +          MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX + KeyValueUtils.KEY_DELIMITER);        for (Entry<String, String> entry : allSPs.entrySet()) {          if (entry.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER)               && entry.getValue().equals(entityId)) { diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/SpringBootBasicConfigurationProvider.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/SpringBootBasicConfigurationProvider.java new file mode 100644 index 00000000..76e2c01f --- /dev/null +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/SpringBootBasicConfigurationProvider.java @@ -0,0 +1,122 @@ +package at.asitplus.eidas.specific.connector.config; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; + +import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.conf.AbstractSpringBootConfigurationImpl; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SpringBootBasicConfigurationProvider extends AbstractSpringBootConfigurationImpl { + +  private final Map<String, ISpConfiguration> spConfigCache = new HashMap<>(); +   +  @Override +  public ISpConfiguration getServiceProviderConfiguration(String entityId) throws EaafConfigurationException { +    if (!spConfigCache.containsKey(entityId)) { +      log.debug("SP: " + entityId + " is NOT cached. Starting load operation ...  "); +      final Map<String, String> allSPs = getBasicConfigurationWithPrefix( +          MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX); +      for (Entry<String, String> entry : allSPs.entrySet()) { +        if (entry.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER)  +            && entry.getValue().equals(entityId)) { +          final String listId = KeyValueUtils.getParentKey(entry.getKey()); +          log.trace("Find SP configuration with list-Id: " + listId +              + ". Extracting configuration elements ... "); +          final Map<String, String> spConfig = KeyValueUtils.getSubSetWithPrefix(allSPs, listId +              + KeyValueUtils.KEY_DELIMITER); +          spConfigCache.put(entityId, +              new ServiceProviderConfiguration(spConfig, this)); +          break; +        } +      } + +      if (spConfigCache.containsKey(entityId)) { +        log.info("SP: " + entityId + " is loaded. Continuing auth. process ... "); +      } else { +        log.warn("SP: " + entityId + " is NOT found in configuration. Stopping auth. process ... "); +        return null; + +      } + +    } else { +      log.trace("SP: " + entityId + " is already cached. Use configuration from there ... "); +    } + +    return spConfigCache.get(entityId); +  } + +  @Override +  public <T> T getServiceProviderConfiguration(String entityId, Class<T> decorator) +      throws EaafConfigurationException { +    final ISpConfiguration spConfig = getServiceProviderConfiguration(entityId); +    if (spConfig != null && decorator != null) { +      if (decorator.isInstance(spConfig)) { +        return (T) spConfig; +      } else { +        log.error("SPConfig: " + spConfig.getClass().getName() + " is NOT instance of: " + decorator +            .getName()); +      } + +    } + +    return null; + +  } + +  @Override +  public String validateIdpUrl(URL url) throws EaafException { +    log.trace("Validate requested URL: " + url); +    String urlPrefixFromConfig = getBasicConfiguration( +        MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX); +    if (StringUtils.isEmpty(urlPrefixFromConfig)) { +      log.warn("Application config containts NO URL prefix"); +      throw new EaafConfigurationException("config.27", +          new Object[] { "Application config containts NO " +              + getApplicationSpecificKeyPrefix() +              + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX }); + +    } + +    // remove last slash +    if (urlPrefixFromConfig.endsWith("/")) { +      urlPrefixFromConfig = urlPrefixFromConfig.substring(0, urlPrefixFromConfig.length() - 1); +    } + +    if (getBasicConfigurationBoolean( +        MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_REQUEST_VALIDATION, false)) { +      if (url != null && url.toExternalForm().startsWith(urlPrefixFromConfig)) { +        return urlPrefixFromConfig; +      } + +      log.info("URL: " + url + " does NOT match to allowed application prefix: " + urlPrefixFromConfig); +      return null; + +    } else { +      return urlPrefixFromConfig; + +    } +  } + +  @Override +  public String getApplicationSpecificKeyPrefix() { +    return MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PREFIX; + +  } + +  @Override +  protected String getBackupConfigPath() { +    return null; + +  } + +} diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/gui/DefaultVelocityGuiBuilderImpl.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/gui/DefaultVelocityGuiBuilderImpl.java index 7abc6fcb..e7ebc92f 100644 --- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/gui/DefaultVelocityGuiBuilderImpl.java +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/gui/DefaultVelocityGuiBuilderImpl.java @@ -33,7 +33,7 @@ import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration;  import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;  import at.gv.egiz.eaaf.core.impl.gui.AbstractVelocityGuiFormBuilderImpl; -@Service("DefaultVelocityGUIBuilderImpl") +@Service("velocityGUIBuilderImpl")  public class DefaultVelocityGuiBuilderImpl extends AbstractVelocityGuiFormBuilderImpl {    private static final Logger log = LoggerFactory.getLogger(DefaultVelocityGuiBuilderImpl.class); diff --git a/connector_lib/src/main/resources/common_gui.beans.xml b/connector_lib/src/main/resources/common_gui.beans.xml new file mode 100644 index 00000000..969a40f7 --- /dev/null +++ b/connector_lib/src/main/resources/common_gui.beans.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" +  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +  xmlns:context="http://www.springframework.org/schema/context" +  xmlns:tx="http://www.springframework.org/schema/tx" +  xmlns:aop="http://www.springframework.org/schema/aop" +  xmlns:task="http://www.springframework.org/schema/task" +  xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd +    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd +    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  +    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> + +  <bean id="contentNegotiationManager" +    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean" +    primary="true"> +    <property name="parameterName" value="mediaType" /> +    <property name="defaultContentType" value="application/json" /> +    <property name="useRegisteredExtensionsOnly" value="false" /> +    <property name="mediaTypes"> +      <map> +        <entry key="json" value="application/json" /> +        <entry key="html" value="text/html" /> +      </map> +    </property> +  </bean> + +  <bean +    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> +    <property name="order" value="1" /> +    <property name="defaultViews"> +      <list> +        <!-- JSON View --> +        <bean +          class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"> +          <property name="contentType" value="application/json" /> +        </bean> +      </list> +    </property> +  </bean> + + +  <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="valitatorWithI18nSupport" +    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> +    <property name="validationMessageSource" +      ref="messageSource" /> +  </bean> + +</beans>
\ No newline at end of file diff --git a/connector_lib/src/test/java/at/asitplus/eidas/specific/connector/test/config/SpringBootBasicConfigurationProviderTest.java b/connector_lib/src/test/java/at/asitplus/eidas/specific/connector/test/config/SpringBootBasicConfigurationProviderTest.java new file mode 100644 index 00000000..4e7e7dd2 --- /dev/null +++ b/connector_lib/src/test/java/at/asitplus/eidas/specific/connector/test/config/SpringBootBasicConfigurationProviderTest.java @@ -0,0 +1,148 @@ +package at.asitplus.eidas.specific.connector.test.config; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +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.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; +import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { +    "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = { "/config/junit_config_1.properties" }) +@ActiveProfiles("springBoot") +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class SpringBootBasicConfigurationProviderTest { + + @Autowired private IConfigurationWithSP basicConfig; +  +  @Test +  public void configPropInfos() { +    Assert.assertEquals("size", 2, MsEidasNodeConstants.COUNTRY_SELECTION_PARAM_WHITELIST.size()); +     +  } +   +  @Test +  public void loadSpNoExist() throws EaafConfigurationException { +    ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( +        RandomStringUtils.randomAlphabetic(5)); +    Assert.assertNull("spConfig", spConfig); +     +  } +   +  @Test +  public void loadSpConfigBasicMode() throws EaafConfigurationException { +    ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration("jUnitTest1"); +     +    Assert.assertNotNull("spConfig", spConfig); +    Assert.assertEquals("uniqueId", "jUnitTest1", spConfig.getUniqueIdentifier()); +    Assert.assertEquals("friendlyName", "NO FRIENDLYNAME SET", spConfig.getFriendlyName()); +    Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); +    String test = RandomStringUtils.randomAlphabetic(5); +    Assert.assertEquals("pvp2.password", "1234pass",  +        spConfig.getConfigurationValue("pvp2.metadata.truststore.password", test)); +    Assert.assertEquals("eidMode", true, spConfig.isConfigurationValue("newEidMode")); +    Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); +    Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); +    Assert.assertEquals("fullConfig", 4, spConfig.getFullConfiguration().size()); +     +  } +   +  @Test +  public void loadSpConfigAdvancedMode() throws EaafConfigurationException { +    ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( +        "jUnitTest2", ServiceProviderConfiguration.class); +     +    Assert.assertNotNull("spConfig", spConfig); +    Assert.assertEquals("uniqueId", "jUnitTest2", spConfig.getUniqueIdentifier()); +    Assert.assertEquals("friendlyName", "jUnit tester 2", spConfig.getFriendlyName()); +    Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); +    String test = RandomStringUtils.randomAlphabetic(5); +    Assert.assertEquals("pvp2.password", test,  +        spConfig.getConfigurationValue("pvp2.metadata.truststore.notexist", test)); +    Assert.assertEquals("eidMode", false, spConfig.isConfigurationValue("newEidMode")); +    Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); +    Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); +    Assert.assertEquals("fullConfig", 5, spConfig.getFullConfiguration().size()); +    Assert.assertFalse("baseIdInternal", spConfig.hasBaseIdInternalProcessingRestriction()); +    Assert.assertTrue("baseIdTransfer", spConfig.hasBaseIdTransferRestriction()); +     +  } +   +  @Test +  public void loadSpConfigAdvancedModeWrongDecorator() throws EaafConfigurationException { +    ISpConfiguration spConfig1 = basicConfig.getServiceProviderConfiguration( +        "jUnitTest2", null);     +    Assert.assertNull("spConfig", spConfig1); + +    String spConfig2 = basicConfig.getServiceProviderConfiguration( +        "jUnitTest2", String.class);     +    Assert.assertNull("spConfig", spConfig2); +     +  } +   +  @Test +  public void loadConfigValuesString() { +    Assert.assertEquals("without default", "ownSpecificConnector",  +        basicConfig.getBasicConfiguration("auth.eIDAS.node_v2.entityId")); +     +    Assert.assertEquals("with default", "",  +        basicConfig.getBasicConfiguration("auth.eIDAS.szrclient.endpoint.prod",  +            RandomStringUtils.randomAlphabetic(5))); +     +    String rand1 = RandomStringUtils.randomAlphanumeric(5); +    Assert.assertEquals("unknown with default", rand1,  +        basicConfig.getBasicConfiguration("notexist", rand1)); +     +  } +   +  @Test +  public void loadConfigValuesBoolean() { +    Assert.assertEquals("without default", true,  +        basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.useTestService")); +     +    Assert.assertEquals("not exist with default", false,  +        basicConfig.getBasicConfigurationBoolean("auth.notexist",  +            false)); +     +    Assert.assertEquals("exist but empty with default", true,  +        basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.params.vkz", true)); +     +  } +   +  @Test +  public void loadConfigMap() { +    Map<String, String> entries = basicConfig.getBasicConfigurationWithPrefix("auth.eIDAS.szrclient"); +    Assert.assertEquals("wrong size", 16, entries.size()); +    Assert.assertTrue("missing element", entries.containsKey("endpoint.test")); +    Assert.assertEquals("wrong entry", "http://localhost:1234/demoszr", entries.get("endpoint.test")); +     +  } +   +  @Test +  public void validateUrl() throws MalformedURLException, EaafException { +    Assert.assertEquals("wrong URL", "http://localhost/test",  +        basicConfig.validateIdpUrl(new URL("http://localhost/test/" + RandomStringUtils.randomAlphabetic(5)))); +    +    Assert.assertNull("wrong URL", +        basicConfig.validateIdpUrl(new URL("http://localhost/wrong/" + RandomStringUtils.randomAlphabetic(5)))); +     +  } +} diff --git a/connector_lib/src/test/resources/SpringTest-context_basic_realConfig.xml b/connector_lib/src/test/resources/SpringTest-context_basic_realConfig.xml index bcca90b5..fbc4640a 100644 --- a/connector_lib/src/test/resources/SpringTest-context_basic_realConfig.xml +++ b/connector_lib/src/test/resources/SpringTest-context_basic_realConfig.xml @@ -11,10 +11,15 @@    <context:annotation-config /> +  <beans profile="!springBoot">    <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="springBoot"> +    <bean id="springBootMsSpecificNodeConfig" +          class="at.asitplus.eidas.specific.connector.config.SpringBootBasicConfigurationProvider" /> +  </beans>  </beans>
\ No newline at end of file diff --git a/connector_lib/src/test/resources/config/junit_config_1.properties b/connector_lib/src/test/resources/config/junit_config_1.properties index 01dcf842..160725d4 100644 --- a/connector_lib/src/test/resources/config/junit_config_1.properties +++ b/connector_lib/src/test/resources/config/junit_config_1.properties @@ -1,6 +1,7 @@  ## Basic service configuration  eidas.ms.context.url.prefix=http://localhost/test/  eidas.ms.context.url.request.validation=true +eidas.ms.core.configRootDir=file:./src/test/resources/config/  eidas.ms.context.use.clustermode=true @@ -19,8 +19,11 @@      <!-- ===================================================================== -->      <egiz-spring-api>0.3</egiz-spring-api>      <egiz-eventlog-slf4jBackend>0.4</egiz-eventlog-slf4jBackend> -    <eaaf-core.version>1.1.10</eaaf-core.version> -    <org.springframework.version>5.2.12.RELEASE</org.springframework.version> +    <eaaf-core.version>1.1.11-SNAPSHOT</eaaf-core.version> + +    <spring-boot-starter-web.version>2.4.1</spring-boot-starter-web.version> +    <spring-boot-admin-starter-client.version>2.3.1</spring-boot-admin-starter-client.version> +    <org.springframework.version>5.3.2</org.springframework.version>      <org.thymeleaf-spring5.version>3.0.11.RELEASE</org.thymeleaf-spring5.version>      <cxf.version>3.4.1</cxf.version> @@ -35,6 +38,9 @@      <jackson-datatype-jsr310.version>2.12.0</jackson-datatype-jsr310.version>      <!-- org.xerial.sqlite-jdbc.version>3.34.0</org.xerial.sqlite-jdbc.version --> +    <javax.validation-api.version>2.0.1.Final</javax.validation-api.version> +    <hibernate-validator.version>6.1.5.Final</hibernate-validator.version> +      <!-- testing -->      <junit.version>4.13.1</junit.version>      <surefire.version>2.22.2</surefire.version> @@ -123,6 +129,11 @@        </dependency>        <dependency>          <groupId>at.gv.egiz.eaaf</groupId> +        <artifactId>eaaf-springboot-utils</artifactId> +        <version>${eaaf-core.version}</version> +      </dependency> +      <dependency> +        <groupId>at.gv.egiz.eaaf</groupId>          <artifactId>eaaf_module_pvp2_idp</artifactId>          <version>${eaaf-core.version}</version>        </dependency> @@ -187,6 +198,27 @@        <!-- Third party libs -->        <dependency> +        <groupId>org.springframework.boot</groupId> +        <artifactId>spring-boot-starter-web</artifactId> +        <version>${spring-boot-starter-web.version}</version> +      </dependency> +      <dependency> +        <groupId>org.springframework.boot</groupId> +        <artifactId>spring-boot-starter-actuator</artifactId> +        <version>${spring-boot-starter-web.version}</version> +      </dependency> +      <dependency> +        <groupId>org.springframework.boot</groupId> +        <artifactId>spring-boot-starter-tomcat</artifactId> +        <version>${spring-boot-starter-web.version}</version> +      </dependency> +      <dependency> +        <groupId>de.codecentric</groupId> +        <artifactId>spring-boot-admin-starter-client</artifactId> +        <version>${spring-boot-admin-starter-client.version}</version> +      </dependency> + +      <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-webmvc</artifactId>          <version>${org.springframework.version}</version> @@ -257,6 +289,16 @@          <artifactId>jackson-datatype-jsr310</artifactId>          <version>${jackson-datatype-jsr310.version}</version>        </dependency> +      <dependency> +        <groupId>javax.validation</groupId> +        <artifactId>validation-api</artifactId> +        <version>${javax.validation-api.version}</version> +      </dependency> +     <dependency> +        <groupId>org.hibernate.validator</groupId> +        <artifactId>hibernate-validator</artifactId> +        <version>${hibernate-validator.version}</version> +      </dependency>        <!-- Testing --> @@ -298,8 +340,8 @@          <version>${egiz.eidas.version}</version>          <scope>test</scope>          <type>test-jar</type> -      </dependency>       -       +      </dependency> +      </dependencies>    </dependencyManagement>    <dependencies> @@ -315,36 +357,36 @@      <finalName>ms-specific_eidas_node</finalName>      <pluginManagement>        <plugins> -      <plugin> -        <groupId>org.apache.maven.plugins</groupId> -        <artifactId>maven-compiler-plugin</artifactId> -        <version>${maven-compiler-plugin.version}</version> -        <configuration> -          <source>1.8</source> -          <target>1.8</target> -        </configuration> -        <executions> -          <execution> -            <goals> -              <goal>compile</goal> -              <goal>testCompile</goal> -            </goals> -          </execution> -        </executions> -      </plugin> -      <plugin> -        <groupId>org.apache.maven.plugins</groupId> -        <artifactId>maven-jar-plugin</artifactId> -        <version>3.1.0</version> -        <executions> -          <execution> -            <goals> -              <goal>test-jar</goal> -            </goals> -          </execution> -        </executions> -      </plugin>         -         +        <plugin> +          <groupId>org.apache.maven.plugins</groupId> +          <artifactId>maven-compiler-plugin</artifactId> +          <version>${maven-compiler-plugin.version}</version> +          <configuration> +            <source>1.8</source> +            <target>1.8</target> +          </configuration> +          <executions> +            <execution> +              <goals> +                <goal>compile</goal> +                <goal>testCompile</goal> +              </goals> +            </execution> +          </executions> +        </plugin> +        <plugin> +          <groupId>org.apache.maven.plugins</groupId> +          <artifactId>maven-jar-plugin</artifactId> +          <version>3.1.0</version> +          <executions> +            <execution> +              <goals> +                <goal>test-jar</goal> +              </goals> +            </execution> +          </executions> +        </plugin> +          <plugin>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-codegen-plugin</artifactId> | 
