Skip to content
Snippets Groups Projects
SecurityConfiguration.java 6.24 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * Copyright (c) 2023-2024.
    
     * Lizenziert unter der EUPL, Version 1.2 oder - sobald
     * diese von der Europäischen Kommission genehmigt wurden -
     * Folgeversionen der EUPL ("Lizenz");
     * Sie dürfen dieses Werk ausschließlich gemäß
     * dieser Lizenz nutzen.
     * Eine Kopie der Lizenz finden Sie hier:
     *
     * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
     *
     * Sofern nicht durch anwendbare Rechtsvorschriften
     * gefordert oder in schriftlicher Form vereinbart, wird
     * die unter der Lizenz verbreitete Software "so wie sie
     * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
     * ausdrücklich oder stillschweigend - verbreitet.
     * Die sprachspezifischen Genehmigungen und Beschränkungen
     * unter der Lizenz sind dem Lizenztext zu entnehmen.
     */
    
    
    package de.ozgcloud.antragsraum;
    
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import org.springframework.security.config.Customizer;
    
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    
    import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
    import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
    import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
    import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
    
    import org.springframework.security.web.SecurityFilterChain;
    
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    
    OZGCloud's avatar
    OZGCloud committed
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
    
    import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
    
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    OZGCloud's avatar
    OZGCloud committed
    import de.ozgcloud.antragsraum.security.AntragsraumLogoutSuccessHandler;
    import de.ozgcloud.antragsraum.security.AntragsraumProperties;
    import de.ozgcloud.antragsraum.security.BayernIdProperties;
    
    import de.ozgcloud.antragsraum.security.BayernIdSaml2Extension;
    
    OZGCloud's avatar
    OZGCloud committed
    import de.ozgcloud.antragsraum.security.JwtTokenFilter;
    
    import de.ozgcloud.antragsraum.security.SamlUrlAuthenticationSuccessHandler;
    
    import de.ozgcloud.antragsraum.security.SecurityProvider;
    
    OZGCloud's avatar
    OZGCloud committed
    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    
    
    @RequiredArgsConstructor
    
    	private static final String OPTIONS = "OPTIONS";
    	private static final String GET = "GET";
    
    	private static final String POLICY_DIRECTIVES = "object-src 'none'; child-src 'self'; frame-ancestors 'none'; base-uri 'none'; upgrade-insecure-requests; require-trusted-types-for 'script'";
    
    OZGCloud's avatar
    OZGCloud committed
    	@NonNull
    
    	private final BayernIdSaml2Extension bayernIdSaml2Extension;
    
    OZGCloud's avatar
    OZGCloud committed
    	@NonNull
    	private final BayernIdProperties bayernIdProperties;
    	@NonNull
    	private final UserDetailsService userDetailsService;
    	@NonNull
    
    OZGCloud's avatar
    OZGCloud committed
    	private final JwtTokenFilter tokenAuthenticationFilter;
    	@NonNull
    
    OZGCloud's avatar
    OZGCloud committed
    	private final AntragsraumProperties properties;
    
    
    	@Bean
    	public SecurityProvider securityProvider() {
    		return new SecurityProvider();
    	}
    
    
    	@Bean
    	public SecurityContextLogoutHandler logoutHandler() {
    		return new SecurityContextLogoutHandler();
    	}
    
    
    OZGCloud's avatar
    OZGCloud committed
    	@Bean
    	Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
    
    		var registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations);
    		var authenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(registrationResolver);
    
    OZGCloud's avatar
    OZGCloud committed
    		authenticationRequestResolver.setAuthnRequestCustomizer(context -> {
    			context.getAuthnRequest().setForceAuthn(true);
    
    			context.getAuthnRequest().setExtensions(bayernIdSaml2Extension.createAkdbExtension());
    
    OZGCloud's avatar
    OZGCloud committed
    		});
    
    
    		return authenticationRequestResolver;
    
    OZGCloud's avatar
    OZGCloud committed
    	}
    
    	@Bean
    	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    		http
    		  .authorizeHttpRequests(authorize -> authorize
    
    			.requestMatchers("/", "/actuator/**", "/swagger-ui/**", "/v3/api-docs/**", "/error", "/favicon.ico", "/auth/**", "/login", "/api/e2e/**")
    			.permitAll()
    
    OZGCloud's avatar
    OZGCloud committed
    			.requestMatchers("/api/**").authenticated()
    			.anyRequest().denyAll())
    
    OZGCloud's avatar
    OZGCloud committed
    		  .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
    
    		  .csrf(AbstractHttpConfigurer::disable)
    		  .headers(headers -> headers.contentSecurityPolicy(
    			csp -> csp.policyDirectives(POLICY_DIRECTIVES)))
    		  .headers(headers -> headers.referrerPolicy(
    			referrerPolicyConfig -> referrerPolicyConfig.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER)));
    
    OZGCloud's avatar
    OZGCloud committed
    
    
    		http.saml2Login(samlLogin -> samlLogin.successHandler(getSamlUrlAuthenticationSuccessHandler()))
    		  .saml2Logout(Customizer.withDefaults())
    		  .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(getLogoutSuccessHandler()));
    
    OZGCloud's avatar
    OZGCloud committed
    
    		return http.build();
    	}
    
    
    	AuthenticationSuccessHandler getSamlUrlAuthenticationSuccessHandler() {
    		return new SamlUrlAuthenticationSuccessHandler(bayernIdProperties.getRedirectUrl(), userDetailsService);
    	}
    
    
    	AntragsraumLogoutSuccessHandler getLogoutSuccessHandler() {
    
    OZGCloud's avatar
    OZGCloud committed
    		var handler = new AntragsraumLogoutSuccessHandler(userDetailsService);
    		handler.setDefaultTargetUrl(properties.getLogoutSuccessUrl());
    
    OZGCloud's avatar
    OZGCloud committed
    		return handler;
    	}
    
    	@Bean
    	public WebMvcConfigurer corsConfigurer() {
    		return new WebMvcConfigurer() {
    			@Override
    			public void addCorsMappings(@NonNull CorsRegistry registry) {
    				registry.addMapping("/auth/**").allowedOrigins(properties.getAuthOrigins())
    				  .allowedMethods(GET, OPTIONS, "POST").allowCredentials(true);
    				registry.addMapping("/api/**").allowedOrigins(properties.getApiOrigins())
    				  .allowedMethods(GET, OPTIONS, "PUT", "POST").allowCredentials(true);
    				registry.addMapping("/**").allowedOrigins(properties.getOtherOrigins()).allowedMethods(GET, OPTIONS)
    				  .allowCredentials(true);
    			}
    		};
    	}