diff --git a/.gitignore b/.gitignore index a5494f7..762a74d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *# *.idea +logs *.iml *.ipr *.iws diff --git a/pom.xml b/pom.xml index 103806b..3896831 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.4 + 3.4.3 com.quickstartdev @@ -14,7 +14,7 @@ Library management system - 17 + 23 @@ -36,7 +36,7 @@ org.thymeleaf.extras - thymeleaf-extras-springsecurity5 + thymeleaf-extras-springsecurity6 org.springframework.boot @@ -75,6 +75,11 @@ spring-security-test test + + org.projectlombok + lombok + provided + @@ -86,4 +91,4 @@ - \ No newline at end of file + diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/controller/FileExportController.java b/src/main/java/com/knf/dev/librarymanagementsystem/controller/FileExportController.java index f201bdd..6c13a11 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/controller/FileExportController.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/controller/FileExportController.java @@ -1,13 +1,11 @@ package com.knf.dev.librarymanagementsystem.controller; -import javax.servlet.http.HttpServletResponse; - +import com.knf.dev.librarymanagementsystem.service.FileService; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import com.knf.dev.librarymanagementsystem.service.FileService; - @Controller public class FileExportController { diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Author.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Author.java index fdcba4c..c6fd270 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Author.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Author.java @@ -1,18 +1,18 @@ package com.knf.dev.librarymanagementsystem.entity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; + import java.util.HashSet; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - @Entity @Table(name = "authors") public class Author { diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Book.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Book.java index 854e262..05c347b 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Book.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Book.java @@ -1,20 +1,20 @@ package com.knf.dev.librarymanagementsystem.entity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; + import java.util.HashSet; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - @Entity @Table(name = "books") public class Book { diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Category.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Category.java index 2bd29b2..6a59ea0 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Category.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Category.java @@ -1,18 +1,18 @@ package com.knf.dev.librarymanagementsystem.entity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; + import java.util.HashSet; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - @Entity @Table(name = "categories") public class Category { diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Publisher.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Publisher.java index 401baf3..9de2904 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Publisher.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Publisher.java @@ -1,18 +1,18 @@ package com.knf.dev.librarymanagementsystem.entity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; + import java.util.HashSet; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - @Entity @Table(name = "publishers") public class Publisher { diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Role.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Role.java index 3e4a52d..be0de37 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/Role.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/Role.java @@ -1,13 +1,13 @@ package com.knf.dev.librarymanagementsystem.entity; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity -@Table(name = "role") +@Table(name = "roles") public class Role { @Id @@ -39,4 +39,4 @@ public String getName() { public void setName(String name) { this.name = name; } -} \ No newline at end of file +} diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/entity/User.java b/src/main/java/com/knf/dev/librarymanagementsystem/entity/User.java index 9de5619..4b5d6c2 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/entity/User.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/entity/User.java @@ -1,22 +1,22 @@ package com.knf.dev.librarymanagementsystem.entity; -import java.util.Collection; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; +import java.util.Collection; @Entity -@Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = "email")) +@Table(name = "users", uniqueConstraints = @UniqueConstraint(columnNames = "email")) public class User { @Id @@ -98,4 +98,4 @@ public Collection getRoles() { public void setRoles(Collection roles) { this.roles = roles; } -} \ No newline at end of file +} diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/AuthenticationFailureHandler.java b/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/AuthenticationFailureHandler.java new file mode 100644 index 0000000..54a13a3 --- /dev/null +++ b/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/AuthenticationFailureHandler.java @@ -0,0 +1,38 @@ +package com.knf.dev.librarymanagementsystem.securityconfig; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +import java.io.IOException; + +/** + * Created by IntelliJ IDEA. + * Project : librarymanagementsystem + * User: hendisantika + * Link: s.id/hendisantika + * Email: hendisantika@yahoo.co.id + * Telegram : @hendisantika34 + * Date: 26/02/25 + * Time: 10.19 + * To change this template use File | Settings | File Templates. + */ +@Slf4j +public class AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, + AuthenticationException exception) throws IOException { + String errorMessage = "failed login attempt. invalid username or password"; + log.error(errorMessage); + if (exception.getMessage().equalsIgnoreCase("blocked")) { + errorMessage = "you have been blocked for 3 unsuccessful login attempt"; + log.error(errorMessage); + } + log.info("path {}", request.getPathInfo()); + response.sendRedirect(request.getPathInfo()); + } + +} diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/SecurityConfiguration.java b/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/SecurityConfiguration.java index 4203b0a..a6e4fbc 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/SecurityConfiguration.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/securityconfig/SecurityConfiguration.java @@ -1,21 +1,22 @@ package com.knf.dev.librarymanagementsystem.securityconfig; +import com.knf.dev.librarymanagementsystem.service.UserService; 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.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; 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.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import com.knf.dev.librarymanagementsystem.service.UserService; - @Configuration @EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { +public class SecurityConfiguration { @Autowired private UserService userService; @@ -33,17 +34,42 @@ public DaoAuthenticationProvider authenticationProvider() { return auth; } - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.authenticationProvider(authenticationProvider()); + @Bean + public AuthenticationFailureHandler authenticationFailureHandler() { + return new com.knf.dev.librarymanagementsystem.securityconfig.AuthenticationFailureHandler(); + } + /* + * Tell Spring Security to use the custom built UserDetailsServiceImpl class + * + */ + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { + return authConfig.getAuthenticationManager(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().antMatchers("/js/**", "/css/**", "/img/**").permitAll().anyRequest().authenticated() - .and().formLogin().loginPage("/login").permitAll().and().logout().invalidateHttpSession(true) - .clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout")) - .logoutSuccessUrl("/login?logout").permitAll(); +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// auth.authenticationProvider(authenticationProvider()); +// } + + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(req -> req + .requestMatchers("/login", "/js/**", "/css/**", "/img/**").permitAll() + .anyRequest().authenticated() + ) + .formLogin(formLogin -> formLogin + .loginPage("/login") //enable this to go to your own custom login page + .loginProcessingUrl("/admin/dashboard") //enable this to use login page provided by spring security + .defaultSuccessUrl("/admin/dashboard", true) + .failureUrl("/login?error") + ) + .logout(logout -> logout + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .logoutSuccessUrl("/login?logout").permitAll() + ); + return http.build(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/service/FileService.java b/src/main/java/com/knf/dev/librarymanagementsystem/service/FileService.java index 7e12999..3054ec5 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/service/FileService.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/service/FileService.java @@ -1,13 +1,12 @@ package com.knf.dev.librarymanagementsystem.service; -import java.io.IOException; - -import javax.servlet.http.HttpServletResponse; - import com.opencsv.exceptions.CsvDataTypeMismatchException; import com.opencsv.exceptions.CsvRequiredFieldEmptyException; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; public interface FileService { - public void exportCSV(String fileName, HttpServletResponse response) + void exportCSV(String fileName, HttpServletResponse response) throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException, IOException; } diff --git a/src/main/java/com/knf/dev/librarymanagementsystem/service/impl/FileServiceImpl.java b/src/main/java/com/knf/dev/librarymanagementsystem/service/impl/FileServiceImpl.java index be05e72..2258233 100644 --- a/src/main/java/com/knf/dev/librarymanagementsystem/service/impl/FileServiceImpl.java +++ b/src/main/java/com/knf/dev/librarymanagementsystem/service/impl/FileServiceImpl.java @@ -1,13 +1,5 @@ package com.knf.dev.librarymanagementsystem.service.impl; -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Service; - import com.knf.dev.librarymanagementsystem.constant.Item; import com.knf.dev.librarymanagementsystem.service.AuthorService; import com.knf.dev.librarymanagementsystem.service.BookService; @@ -24,6 +16,12 @@ import com.opencsv.bean.StatefulBeanToCsvBuilder; import com.opencsv.exceptions.CsvDataTypeMismatchException; import com.opencsv.exceptions.CsvRequiredFieldEmptyException; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.io.PrintWriter; @Service public class FileServiceImpl implements FileService { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 30adec3..4163976 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,5 @@ server.port=9080 -server.error.whitelabel.enabled=false \ No newline at end of file +server.error.whitelabel.enabled=false +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.generate-ddl=true