All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.ikor.sip.foundation.security.config.SecurityConfig Maven / Gradle / Ivy

package de.ikor.sip.foundation.security.config;

import de.ikor.sip.foundation.core.util.exception.SIPFrameworkException;
import de.ikor.sip.foundation.security.authentication.CompositeAuthenticationFilter;
import de.ikor.sip.foundation.security.authentication.SIPAuthenticationProvider;
import de.ikor.sip.foundation.security.authentication.common.extractors.TokenExtractors;
import de.ikor.sip.foundation.security.config.SecurityConfigProperties.AuthProviderSettings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.authentication.AuthenticationManagerBeanDefinitionParser.NullAuthenticationProvider;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * Central place of all configs related for spring-security settings regarding the sip
 * authentication features
 */
@Configuration
public class SecurityConfig {

  private final List> authProviders;

  private final SecurityConfigProperties config;

  private final TokenExtractors tokenExtractors;

  /**
   * Autowired constructor for creating SIP Security Configuration
   *
   * @param authProviders (optional) list of auth providers defined in the config
   * @param config SIP Security config
   * @param tokenExtractors (optional) registered token extractors filled by authProviders
   */
  @Autowired
  public SecurityConfig(
      Optional>> authProviders,
      SecurityConfigProperties config,
      Optional tokenExtractors) {
    this.authProviders = authProviders.orElse(Collections.emptyList());
    this.config = config;
    this.tokenExtractors = tokenExtractors.orElse(null);
  }

  /**
   * Register custom authenticationManager as a @Bean
   *
   * @return Spring's Authentication Manager
   * @throws SIPFrameworkException due to misconfiguration
   */
  @Bean
  public AuthenticationManager authenticationManagerBean() throws SIPFrameworkException {
    List> autowiredAuthProviders =
        List.copyOf(authProviders.stream().map(Object::getClass).toList());

    List> providersUnavailableAtRuntime =
        List.copyOf(
            config.getAuthProviders().stream()
                .map(AuthProviderSettings::getClassname)
                .filter(a -> !autowiredAuthProviders.contains(a))
                .toList());

    if (!providersUnavailableAtRuntime.isEmpty()) {
      throw SIPFrameworkException.init(
          "Some providers declared in the config are not available in runtime: %s",
          providersUnavailableAtRuntime);
    }

    if (configHasDuplicateAuthProviders()) {
      throw new SIPFrameworkException(
          "Each auth provider may only be configured once, duplicates are not allowed");
    }
    if (authProviders.isEmpty()) {
      return new ProviderManager(new NullAuthenticationProvider());
    }
    // Register all auth providers that exist in the config
    List authenticationProviders = new ArrayList<>();
    authProviders.stream()
        .filter(
            a ->
                config.getAuthProviders().stream()
                    .map(AuthProviderSettings::getClassname)
                    .anyMatch(n -> n.equals(a.getClass())))
        .forEach(authenticationProviders::add);
    return new ProviderManager(authenticationProviders);
  }

  private boolean configHasDuplicateAuthProviders() {
    return config.getAuthProviders().size()
        > config.getAuthProviders().stream()
            .map(AuthProviderSettings::getClassname)
            .distinct()
            .count();
  }

  /**
   * @param http Spring provided http security object used for configuring rules
   * @return Spring's SecurityFilterChain
   * @throws Exception if security isn't properly configured
   */
  @Bean
  public SecurityFilterChain sipDefaultSecurityFilterChain(HttpSecurity http) throws Exception {
    // disable sessions completely
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    // add our composite authentication Filter for all requests (besides the ones ignored separately
    // in the WebSecurity configure method
    if (config.isDisableCsrf()) {
      http.csrf().disable();
    }

    http.addFilterAt(
            new CompositeAuthenticationFilter(tokenExtractors, config, authenticationManagerBean()),
            BasicAuthenticationFilter.class)
        .authorizeHttpRequests()
        .anyRequest()
        .authenticated();

    return http.build();
  }

  /**
   * Set globally ignored endpoints from config
   *
   * @return Spring WebSecurityCustomizer
   */
  @Bean
  public WebSecurityCustomizer sipDefaultWebSecurityCustomizer() {
    return (web -> {
      final WebSecurity.IgnoredRequestConfigurer ignoredRequestConfigurer = web.ignoring();
      config
          .getIgnoredEndpoints()
          .forEach(
              endpoint ->
                  ignoredRequestConfigurer.requestMatchers(
                      AntPathRequestMatcher.antMatcher(endpoint)));
    });
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy