Skip to content

Instantly share code, notes, and snippets.

@ram0973
Created November 30, 2023 05:37
Show Gist options
  • Select an option

  • Save ram0973/06cc136315e90d8acb8c8c7e7f80958c to your computer and use it in GitHub Desktop.

Select an option

Save ram0973/06cc136315e90d8acb8c8c7e7f80958c to your computer and use it in GitHub Desktop.

Revisions

  1. ram0973 created this gist Nov 30, 2023.
    153 changes: 153 additions & 0 deletions SecurityConfig.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,153 @@
    package com.me.springapp.configuration;

    import com.me.springapp.exceptions.NoSuchEntityException;
    import com.me.springapp.model.User;
    import com.me.springapp.security.service.UserDetailsServiceImpl;
    import com.me.springapp.security.userdetails.UserDetailsImpl;
    import com.me.springapp.service.UserService;
    import lombok.RequiredArgsConstructor;
    import org.jetbrains.annotations.NotNull;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
    import org.springframework.security.authentication.*;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.factory.PasswordEncoderFactories;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    import org.springframework.security.web.util.matcher.RequestMatcher;
    import org.springframework.stereotype.Service;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.servlet.LocaleResolver;
    import org.springframework.web.servlet.i18n.SessionLocaleResolver;

    import javax.sql.DataSource;
    import java.util.List;
    import java.util.Locale;

    // https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html
    @Configuration
    //@EnableWebSecurity
    @RequiredArgsConstructor
    public class SecurityConfig {

    private final AuthenticationProvider authenticationProvider;
    private final DataSource dataSource;
    private final UserDetailsService userDetailsService;
    static final String PROJECT_LANGUAGE = "ru"; //TODO move to ini
    static final String[] ALLOWED_ORIGINS = {"http://localhost:8080"}; //TODO move to ini

    // resolve ${} in @Value
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfig() {
    return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public LocaleResolver localeResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    sessionLocaleResolver.setDefaultLocale(Locale.forLanguageTag(PROJECT_LANGUAGE));
    return sessionLocaleResolver;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }


    // @Bean
    // public AuthenticationProvider authenticationProvider(UserDetailsServiceImpl userDetailsService) {
    // DaoAuthenticationProvider provider = new DaoAuthenticationProvider(passwordEncoder());
    // provider.setUserDetailsService(userDetailsService);
    // return provider;
    // }
    //
    // @Bean
    // public AuthenticationManager authenticationManager(UserDetailsService userDetailsService,
    // PasswordEncoder passwordEncoder) {
    // DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
    // authenticationProvider.setUserDetailsService(userDetailsService);
    // authenticationProvider.setPasswordEncoder(passwordEncoder);
    // return new ProviderManager(authenticationProvider);
    // }

    // @Bean
    // CorsConfigurationSource corsConfigurationSource() {
    // CorsConfiguration config = new CorsConfiguration();
    // config.setAllowCredentials(true);
    // config.setAllowedOrigins(List.of(ALLOWED_ORIGINS));
    // config.addAllowedHeader("*");
    // config.addAllowedMethod("*");
    // UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // source.registerCorsConfiguration("/**", config);
    // return source;
    // }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    jdbcTokenRepository.setDataSource(dataSource);
    return jdbcTokenRepository;
    }

    @Bean
    protected SecurityFilterChain filterChain(@NotNull HttpSecurity http) throws Exception {
    http
    .authorizeHttpRequests(authorize -> authorize
    .requestMatchers("/blog/**").permitAll()
    .requestMatchers("/", "/api/auth/login", "/api/auth/token").permitAll()
    .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
    .anyRequest().permitAll()
    //.anyRequest().authenticated()
    )
    // https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html
    // https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-mobile
    // check paths
    .csrf(AbstractHttpConfigurer::disable // TODO remove after testing
    //.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    )

    .rememberMe(rememberMe -> rememberMe
    .userDetailsService(userDetailsService)
    .key("1234567890") // TODO Change key
    .tokenRepository(persistentTokenRepository())
    )

    .formLogin(AbstractHttpConfigurer::disable)
    // https://docs.spring.io/spring-security/reference/servlet/authentication/logout.html
    .logout(logout -> logout
    .logoutRequestMatcher(new AntPathRequestMatcher("/api/auth/logout"))
    .logoutUrl("/api/auth/logout").permitAll()
    .logoutSuccessUrl("/").permitAll()
    .invalidateHttpSession(true)
    .deleteCookies("JSESSIONID")
    )
    .passwordManagement(AbstractHttpConfigurer::disable)
    .httpBasic(AbstractHttpConfigurer::disable)

    // https://docs.spring.io/spring-security/reference/servlet/authentication/rememberme.html
    .sessionManagement(sessionManagement ->
    sessionManagement
    .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
    .sessionConcurrency(sessionConcurrency -> sessionConcurrency.maximumSessions(5)
    //.expiredUrl("/login?expired")
    )
    );

    //http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class);
    return http.build();
    }
    }