Newer
Older

OZGCloud
committed
/*
* Copyright (c) 2023-2024.

OZGCloud
committed
* 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;

OZGCloud
committed
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;

OZGCloud
committed
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;

OZGCloud
committed
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
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
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;
import de.ozgcloud.antragsraum.security.JwtTokenFilter;
import de.ozgcloud.antragsraum.security.SamlUrlAuthenticationSuccessHandler;
import de.ozgcloud.antragsraum.security.SecurityProvider;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

OZGCloud
committed
@Configuration
@EnableWebSecurity

OZGCloud
committed
public class SecurityConfiguration {
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'";
private final BayernIdSaml2Extension bayernIdSaml2Extension;
@NonNull
private final BayernIdProperties bayernIdProperties;
@NonNull
private final UserDetailsService userDetailsService;
@NonNull
private final JwtTokenFilter tokenAuthenticationFilter;
@NonNull
@Bean
public SecurityProvider securityProvider() {
return new SecurityProvider();
}
@Bean
public SecurityContextLogoutHandler logoutHandler() {
return new SecurityContextLogoutHandler();
}
@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
var registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations);
var authenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(registrationResolver);
authenticationRequestResolver.setAuthnRequestCustomizer(context -> {
context.getAuthnRequest().setForceAuthn(true);
context.getAuthnRequest().setExtensions(bayernIdSaml2Extension.createAkdbExtension());
}
@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()
.requestMatchers("/api/**").authenticated()
.anyRequest().denyAll())
.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)));
http.saml2Login(samlLogin -> samlLogin.successHandler(getSamlUrlAuthenticationSuccessHandler()))
.saml2Logout(Customizer.withDefaults())
.logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(getLogoutSuccessHandler()));
AuthenticationSuccessHandler getSamlUrlAuthenticationSuccessHandler() {
return new SamlUrlAuthenticationSuccessHandler(bayernIdProperties.getRedirectUrl(), userDetailsService);
}
AntragsraumLogoutSuccessHandler getLogoutSuccessHandler() {
var handler = new AntragsraumLogoutSuccessHandler(userDetailsService);
handler.setDefaultTargetUrl(properties.getLogoutSuccessUrl());
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);
}
};
}