// Path: server/src/main/java/com/bfwg/model/User.java
// @Entity
// @Table(name = "USER")
// public class User implements UserDetails, Serializable {
//     @Id
//     @Column(name = "id")
//     @GeneratedValue(strategy = GenerationType.IDENTITY)
//     private Long id;
// 
//     @Column(name = "username")
//     private String username;
// 
//     @JsonIgnore
//     @Column(name = "password")
//     private String password;
// 
//     @Column(name = "firstname")
//     private String firstname;
// 
//     @Column(name = "lastname")
//     private String lastname;
// 
// 
//     @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
//     @JoinTable(name = "user_authority",
//             joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
//             inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))
//     private List<Authority> authorities;
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void setId(Long id) {
//         this.id = id;
//     }
// 
//     public String getUsername() {
//         return username;
//     }
// 
//     public void setUsername(String username) {
//         this.username = username;
//     }
// 
//     public String getPassword() {
//         return password;
//     }
// 
//     public void setPassword(String password) {
//         this.password = password;
//     }
// 
//     public String getFirstname() {
//         return firstname;
//     }
// 
//     public void setFirstname(String firstname) {
//         this.firstname = firstname;
//     }
// 
//     public String getLastname() {
//         return lastname;
//     }
// 
//     public void setLastname(String lastname) {
//         this.lastname = lastname;
//     }
// 
//     @Override
//     public Collection<? extends GrantedAuthority> getAuthorities() {
//         return this.authorities;
//     }
// 
//     public void setAuthorities(List<Authority> authorities) {
//         this.authorities = authorities;
//     }
// 
//     // We can add the below fields in the users table.
//     // For now, they are hardcoded.
//     @JsonIgnore
//     @Override
//     public boolean isAccountNonExpired() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isAccountNonLocked() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isCredentialsNonExpired() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isEnabled() {
//         return true;
//     }
// }
// 
// Path: server/src/main/java/com/bfwg/service/impl/CustomUserDetailsService.java
// @Service
// public class CustomUserDetailsService implements UserDetailsService {
// 
//     private final UserRepository userRepository;
// 
//     @Autowired
//     public CustomUserDetailsService(UserRepository userRepository) {
//         this.userRepository = userRepository;
//     }
// 
//     @Override
//     public User loadUserByUsername(String username) throws UsernameNotFoundException {
//         return userRepository.findByUsername(username)
//                 .orElseThrow(() -> new UsernameNotFoundException(String.format("No user found with username '%s'.", username)));
//     }
// 
// 
//     public void save(User user) {
//         userRepository.save(user);
//     }
// }


import com.bfwg.model.User;
import com.bfwg.security.auth.*;
import com.bfwg.service.impl.CustomUserDetailsService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
  private final AuthenticationFailureHandler authenticationFailureHandler;
  @Value("${jwt.cookie}")
  private String TOKEN_COOKIE;

  @Autowired
  public WebSecurityConfig(CustomUserDetailsService jwtUserDetailsService, RestAuthenticationEntryPoint restAuthenticationEntryPoint, LogoutSuccess logoutSuccess, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
    this.jwtUserDetailsService = jwtUserDetailsService;
    this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
    this.logoutSuccess = logoutSuccess;
    this.authenticationSuccessHandler = authenticationSuccessHandler;
    this.authenticationFailureHandler = authenticationFailureHandler;
  }

  @Bean
  public TokenAuthenticationFilter jwtAuthenticationTokenFilter() throws Exception {
    return new TokenAuthenticationFilter();
  }

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Autowired
// Path: server/src/main/java/com/bfwg/model/User.java
// @Entity
// @Table(name = "USER")
// public class User implements UserDetails, Serializable {
//     @Id
//     @Column(name = "id")
//     @GeneratedValue(strategy = GenerationType.IDENTITY)
//     private Long id;
// 
//     @Column(name = "username")
//     private String username;
// 
//     @JsonIgnore
//     @Column(name = "password")
//     private String password;
// 
//     @Column(name = "firstname")
//     private String firstname;
// 
//     @Column(name = "lastname")
//     private String lastname;
// 
// 
//     @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
//     @JoinTable(name = "user_authority",
//             joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
//             inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))
//     private List<Authority> authorities;
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void setId(Long id) {
//         this.id = id;
//     }
// 
//     public String getUsername() {
//         return username;
//     }
// 
//     public void setUsername(String username) {
//         this.username = username;
//     }
// 
//     public String getPassword() {
//         return password;
//     }
// 
//     public void setPassword(String password) {
//         this.password = password;
//     }
// 
//     public String getFirstname() {
//         return firstname;
//     }
// 
//     public void setFirstname(String firstname) {
//         this.firstname = firstname;
//     }
// 
//     public String getLastname() {
//         return lastname;
//     }
// 
//     public void setLastname(String lastname) {
//         this.lastname = lastname;
//     }
// 
//     @Override
//     public Collection<? extends GrantedAuthority> getAuthorities() {
//         return this.authorities;
//     }
// 
//     public void setAuthorities(List<Authority> authorities) {
//         this.authorities = authorities;
//     }
// 
//     // We can add the below fields in the users table.
//     // For now, they are hardcoded.
//     @JsonIgnore
//     @Override
//     public boolean isAccountNonExpired() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isAccountNonLocked() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isCredentialsNonExpired() {
//         return true;
//     }
// 
//     @JsonIgnore
//     @Override
//     public boolean isEnabled() {
//         return true;
//     }
// }
// 
// Path: server/src/main/java/com/bfwg/service/impl/CustomUserDetailsService.java
// @Service
// public class CustomUserDetailsService implements UserDetailsService {
// 
//     private final UserRepository userRepository;
// 
//     @Autowired
//     public CustomUserDetailsService(UserRepository userRepository) {
//         this.userRepository = userRepository;
//     }
// 
//     @Override
//     public User loadUserByUsername(String username) throws UsernameNotFoundException {
//         return userRepository.findByUsername(username)
//                 .orElseThrow(() -> new UsernameNotFoundException(String.format("No user found with username '%s'.", username)));
//     }
// 
// 
//     public void save(User user) {
//         userRepository.save(user);
//     }
// }


// Path: server/src/main/java/com/bfwg/config/WebSecurityConfig.java
import com.bfwg.model.User;
import com.bfwg.security.auth.*;
import com.bfwg.service.impl.CustomUserDetailsService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

  private final AuthenticationFailureHandler authenticationFailureHandler;
  @Value("${jwt.cookie}")
  private String TOKEN_COOKIE;

  @Autowired
  public WebSecurityConfig(CustomUserDetailsService jwtUserDetailsService, RestAuthenticationEntryPoint restAuthenticationEntryPoint, LogoutSuccess logoutSuccess, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
    this.jwtUserDetailsService = jwtUserDetailsService;
    this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
    this.logoutSuccess = logoutSuccess;
    this.authenticationSuccessHandler = authenticationSuccessHandler;
    this.authenticationFailureHandler = authenticationFailureHandler;
  }

  @Bean
  public TokenAuthenticationFilter jwtAuthenticationTokenFilter() throws Exception {
    return new TokenAuthenticationFilter();
  }

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder)