From 9c6cc32300db2112108bb067fe5e709a471c5111 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 7 Oct 2024 20:22:18 +0530 Subject: [PATCH 1/9] Login and Logout Feature --- .../security/CustomUserDetailsService.java | 22 +++++++ .../security/JwtAuthenticationFilter.java | 59 +++++++++++++++++++ .../security/JwtAuthenticationHelper.java | 47 +++++++++++++++ .../libraryman_api/security/LoginRequest.java | 28 +++++++++ .../security/LoginResponse.java | 21 +++++++ .../libraryman_api/security/LoginService.java | 47 +++++++++++++++ .../security/SignupService.java | 41 +++++++++++++ .../security/WebConfiguration.java | 39 ++++++++++++ .../application-production.properties | 12 +++- 9 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/libraryman_api/security/CustomUserDetailsService.java create mode 100644 src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java create mode 100644 src/main/java/com/libraryman_api/security/LoginRequest.java create mode 100644 src/main/java/com/libraryman_api/security/LoginResponse.java create mode 100644 src/main/java/com/libraryman_api/security/LoginService.java create mode 100644 src/main/java/com/libraryman_api/security/SignupService.java diff --git a/src/main/java/com/libraryman_api/security/CustomUserDetailsService.java b/src/main/java/com/libraryman_api/security/CustomUserDetailsService.java new file mode 100644 index 0000000..ace26e7 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/CustomUserDetailsService.java @@ -0,0 +1,22 @@ +package com.libraryman_api.security; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.libraryman_api.member.MemberRepository; +@Service +public class CustomUserDetailsService implements UserDetailsService{ + + @Autowired + MemberRepository memberRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + + return memberRepository.findByUsername(username).orElseThrow(()-> new UsernameNotFoundException("Username not Found")); + } + +} diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java b/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..c8fdbe4 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java @@ -0,0 +1,59 @@ +package com.libraryman_api.security; + + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + JwtAuthenticationHelper jwtHelper; + + @Autowired + UserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + String requestHeader=request.getHeader("Authorization"); + String username=null; + String token=null; + if(requestHeader!=null && requestHeader.startsWith("Bearer ")) { + token=requestHeader.substring(7); + username=jwtHelper.getUsernameFromToken(token); + if(username!=null && SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails=userDetailsService.loadUserByUsername(username); + if(!(jwtHelper.isTokenExpired(token))) { + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); + + } + else { + System.out.println("Token is expired or user details not found."); + } + } + + } + filterChain.doFilter(request, response); + } + + + + +} diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java b/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java new file mode 100644 index 0000000..9e95e4c --- /dev/null +++ b/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java @@ -0,0 +1,47 @@ +package com.libraryman_api.security; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.spec.SecretKeySpec; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +@Component +public class JwtAuthenticationHelper { + + private static final long JWT_TOKEN_VALIDITY=60*60; + private String secret="thisisacodingninjasdemonstrationforsecretkeyinspringsecurityjsonwebtokenauthentication"; + public String getUsernameFromToken(String token) { + String username=getClaimsFromToken(token).getSubject(); + return username; + } + + public Claims getClaimsFromToken(String token) { + Claims claims=Jwts.parserBuilder() + .setSigningKey(secret.getBytes()) + .build().parseClaimsJws(token).getBody(); + return claims; + } + + public Boolean isTokenExpired(String token) { + Claims claims=getClaimsFromToken(token); + Date expDate=claims.getExpiration(); + return expDate.before(new Date()); + } + + public String generateToken(UserDetails userDetails) { + Map claims=new HashMap<>(); + return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis()+JWT_TOKEN_VALIDITY*1000)) + .signWith(new SecretKeySpec(secret.getBytes(),SignatureAlgorithm.HS512.getJcaName()),SignatureAlgorithm.HS512) + .compact(); + } +} diff --git a/src/main/java/com/libraryman_api/security/LoginRequest.java b/src/main/java/com/libraryman_api/security/LoginRequest.java new file mode 100644 index 0000000..16e70b9 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/LoginRequest.java @@ -0,0 +1,28 @@ +package com.libraryman_api.security; + +public class LoginRequest { + + private String username; + + private String password; + + + + 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; + } + + +} diff --git a/src/main/java/com/libraryman_api/security/LoginResponse.java b/src/main/java/com/libraryman_api/security/LoginResponse.java new file mode 100644 index 0000000..9488d64 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/LoginResponse.java @@ -0,0 +1,21 @@ +package com.libraryman_api.security; + + +public class LoginResponse { + + private String token; + + public LoginResponse(String token) { + this.token=token; + } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + + +} diff --git a/src/main/java/com/libraryman_api/security/LoginService.java b/src/main/java/com/libraryman_api/security/LoginService.java new file mode 100644 index 0000000..020c5a5 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/LoginService.java @@ -0,0 +1,47 @@ +package com.libraryman_api.security; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +import com.libraryman_api.member.MemberRepository; + + +@Service +public class LoginService { + + @Autowired + AuthenticationManager authenticationManager; + + @Autowired + UserDetailsService userDetailsService; + + @Autowired + JwtAuthenticationHelper jwtHelper; + + @Autowired + MemberRepository memberRepository; + + public LoginResponse login(LoginRequest loginRequest) { + Authenticate(loginRequest.getUsername(), loginRequest.getPassword()); + UserDetails userDetails=userDetailsService.loadUserByUsername(loginRequest.getUsername()); + String token=jwtHelper.generateToken(userDetails); + LoginResponse loginResponse=new LoginResponse(token); + return loginResponse; + } + + public void Authenticate(String username,String password) { + UsernamePasswordAuthenticationToken authenticateToken=new UsernamePasswordAuthenticationToken(username, password); + try { + authenticationManager.authenticate(authenticateToken); + } + catch(BadCredentialsException e){ + throw new BadCredentialsException("Invalid Username or Password"); + } + } +} diff --git a/src/main/java/com/libraryman_api/security/SignupService.java b/src/main/java/com/libraryman_api/security/SignupService.java new file mode 100644 index 0000000..df30b7c --- /dev/null +++ b/src/main/java/com/libraryman_api/security/SignupService.java @@ -0,0 +1,41 @@ +package com.libraryman_api.security; + +import java.util.Date; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +import com.libraryman_api.exception.ResourceNotFoundException; +import com.libraryman_api.member.MemberRepository; +import com.libraryman_api.member.Members; + +@Service +public class SignupService { + + @Autowired + MemberRepository memberRepository; + + @Autowired + PasswordEncoder passwordEncoder; + public void signup(Members members) { + Optional memberOptId=memberRepository.findById(members.getMemberId()); + Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); + if(memberOptId.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + if(memberOptUsername.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); + Members new_members=new Members(); + new_members.setEmail(members.getEmail()); + new_members.setName(members.getName()); + new_members.setPassword(encoded_password); + new_members.setRole(members.getRole()); + new_members.setMembershipDate(new Date()); + new_members.setUsername(members.getUsername()); + memberRepository.save(new_members); + } +} diff --git a/src/main/java/com/libraryman_api/security/WebConfiguration.java b/src/main/java/com/libraryman_api/security/WebConfiguration.java index a0b6518..b086157 100644 --- a/src/main/java/com/libraryman_api/security/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/WebConfiguration.java @@ -7,6 +7,14 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; +<<<<<<< Updated upstream +======= +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +>>>>>>> Stashed changes import static com.libraryman_api.member.Role.ADMIN; import static org.springframework.security.config.Customizer.withDefaults; @@ -30,4 +38,35 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { .formLogin(withDefaults()); return http.build(); } +<<<<<<< Updated upstream +======= + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration builder) throws Exception { + return builder.getAuthenticationManager(); + } + @Bean + public CorsConfigurationSource corsConfigurationSource() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowCredentials(true); + corsConfiguration.addAllowedOriginPattern("*"); + corsConfiguration.addAllowedHeader("Authorization"); + corsConfiguration.addAllowedHeader("Content-Type"); + corsConfiguration.addAllowedHeader("Accept"); + corsConfiguration.addAllowedMethod("POST"); + corsConfiguration.addAllowedMethod("PUT"); + corsConfiguration.addAllowedMethod("GET"); + corsConfiguration.addAllowedMethod("DELETE"); + corsConfiguration.addAllowedMethod("OPTIONS"); + corsConfiguration.setMaxAge(3600L); + + source.registerCorsConfiguration("/**", corsConfiguration); + return source; + } + + @Bean + public CorsFilter corsFilter() { + return new CorsFilter(corsConfigurationSource()); + } +>>>>>>> Stashed changes } diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 6b8edc4..83df9f5 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -14,4 +14,14 @@ spring.mail.username=${MAIL_SERVICE_USERNAME} spring.mail.password=${MAIL_SERVICE_PASSWORD} spring.mail.properties.mail.smtp.auth=${MAIL_SERVICE_SMTP} spring.mail.properties.mail.starttls.enable=${MAIL_SERVICE_STARTTLS} -spring.mail.properties.domain_name=${MAIL_SERVICE_DOMAIN_NAME} \ No newline at end of file +<<<<<<< Updated upstream +spring.mail.properties.domain_name=${MAIL_SERVICE_DOMAIN_NAME} +======= +spring.mail.properties.domain_name=${MAIL_SERVICE_DOMAIN_NAME} + +# --- Oauth 2.0 Configurations --- +spring.security.oauth2.client.registration.google.client-name=google +spring.security.oauth2.client.registration.google.client-id=${YOUR_CLIENT_ID} +spring.security.oauth2.client.registration.google.client-secret=${YOUR_SECRET_KEY} +spring.security.oauth2.client.registration.google.scope=email,profile +>>>>>>> Stashed changes From 3fd9c8f9e8227e334cf3d9d5d402a66f953b7997 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 7 Oct 2024 20:26:22 +0530 Subject: [PATCH 2/9] Login and Logout Feature --- src/main/java/com/libraryman_api/member/Members.java | 11 +++++++++++ .../com/libraryman_api/security/WebConfiguration.java | 5 ++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/libraryman_api/member/Members.java b/src/main/java/com/libraryman_api/member/Members.java index f11b805..499e9e2 100644 --- a/src/main/java/com/libraryman_api/member/Members.java +++ b/src/main/java/com/libraryman_api/member/Members.java @@ -33,6 +33,8 @@ public class Members { @Column(name = "membership_date") private Date membershipDate; + @Column(name = "username") + private String username; public Members() { @@ -89,4 +91,13 @@ public Date getMembershipDate() { public void setMembershipDate(Date membershipDate) { this.membershipDate = membershipDate; } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + } diff --git a/src/main/java/com/libraryman_api/security/WebConfiguration.java b/src/main/java/com/libraryman_api/security/WebConfiguration.java index b086157..e15cefb 100644 --- a/src/main/java/com/libraryman_api/security/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/WebConfiguration.java @@ -38,8 +38,7 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { .formLogin(withDefaults()); return http.build(); } -<<<<<<< Updated upstream -======= + @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration builder) throws Exception { return builder.getAuthenticationManager(); @@ -68,5 +67,5 @@ public CorsConfigurationSource corsConfigurationSource() { public CorsFilter corsFilter() { return new CorsFilter(corsConfigurationSource()); } ->>>>>>> Stashed changes + } From 163007df365cb905a2b2a5f87fa0be9ac583eb75 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 7 Oct 2024 20:33:43 +0530 Subject: [PATCH 3/9] Updated Login and Register functionality --- pom.xml | 18 +++++++++++++++++- .../member/MemberRepository.java | 1 + .../com/libraryman_api/member/Members.java | 14 +++++++++++++- .../security/WebConfiguration.java | 6 +++--- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index eb72bdc..756dfe8 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,23 @@ runtime true - + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + com.mysql diff --git a/src/main/java/com/libraryman_api/member/MemberRepository.java b/src/main/java/com/libraryman_api/member/MemberRepository.java index fffa8d8..2c02216 100644 --- a/src/main/java/com/libraryman_api/member/MemberRepository.java +++ b/src/main/java/com/libraryman_api/member/MemberRepository.java @@ -10,6 +10,7 @@ public interface MemberRepository extends JpaRepository { Optional findByMemberId(int memberId); + Optional findByUsername(String username); /** * SELECT SUM(amount) AS totalFines diff --git a/src/main/java/com/libraryman_api/member/Members.java b/src/main/java/com/libraryman_api/member/Members.java index 499e9e2..ba222f5 100644 --- a/src/main/java/com/libraryman_api/member/Members.java +++ b/src/main/java/com/libraryman_api/member/Members.java @@ -2,11 +2,17 @@ import jakarta.persistence.*; +import java.util.Collection; +import java.util.Collections; import java.util.Date; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + @Entity -public class Members { +public class Members implements UserDetails{ @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, @@ -99,5 +105,11 @@ public String getUsername() { public void setUsername(String username) { this.username = username; } + + @Override + public Collection getAuthorities() { + // TODO Auto-generated method stub + return Collections.singletonList(new SimpleGrantedAuthority(role.name())); + } } diff --git a/src/main/java/com/libraryman_api/security/WebConfiguration.java b/src/main/java/com/libraryman_api/security/WebConfiguration.java index e15cefb..19f971d 100644 --- a/src/main/java/com/libraryman_api/security/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/WebConfiguration.java @@ -3,18 +3,18 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +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.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; -<<<<<<< Updated upstream -======= import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; ->>>>>>> Stashed changes + import static com.libraryman_api.member.Role.ADMIN; import static org.springframework.security.config.Customizer.withDefaults; From 4dc24741b1a3c734f1fd076a679367c5753d1d4b Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 7 Oct 2024 20:34:59 +0530 Subject: [PATCH 4/9] Updated Security Functionality --- src/main/resources/application-production.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 83df9f5..76adb12 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -14,9 +14,7 @@ spring.mail.username=${MAIL_SERVICE_USERNAME} spring.mail.password=${MAIL_SERVICE_PASSWORD} spring.mail.properties.mail.smtp.auth=${MAIL_SERVICE_SMTP} spring.mail.properties.mail.starttls.enable=${MAIL_SERVICE_STARTTLS} -<<<<<<< Updated upstream spring.mail.properties.domain_name=${MAIL_SERVICE_DOMAIN_NAME} -======= spring.mail.properties.domain_name=${MAIL_SERVICE_DOMAIN_NAME} # --- Oauth 2.0 Configurations --- @@ -24,4 +22,4 @@ spring.security.oauth2.client.registration.google.client-name=google spring.security.oauth2.client.registration.google.client-id=${YOUR_CLIENT_ID} spring.security.oauth2.client.registration.google.client-secret=${YOUR_SECRET_KEY} spring.security.oauth2.client.registration.google.scope=email,profile ->>>>>>> Stashed changes + From 0877d91428cdcaee54770d7fb1cf76db17e93fcf Mon Sep 17 00:00:00 2001 From: Rishabh Date: Tue, 8 Oct 2024 21:37:28 +0530 Subject: [PATCH 5/9] Login and Logout Functionality Implemented --- pom.xml | 29 +++++++++------ .../libraryman_api/book/BookController.java | 4 +++ .../borrowing/BorrowingController.java | 5 +++ .../member/MemberController.java | 4 +++ .../com/libraryman_api/member/Members.java | 8 +++-- .../security/JwtAuthenticationFilter.java | 13 ++++--- .../security/JwtAuthenticationHelper.java | 2 +- .../security/LoginController.java | 35 ++++++++++++++----- .../libraryman_api/security/LoginService.java | 21 +++++------ .../security/LogoutController.java | 34 ++++++++++++++++++ .../security/SignupController.java | 21 +++++++++++ .../security/SignupService.java | 13 ++++--- .../security/WebConfiguration.java | 27 ++++++++++---- 13 files changed, 167 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/libraryman_api/security/LogoutController.java diff --git a/pom.xml b/pom.xml index 756dfe8..4a22100 100644 --- a/pom.xml +++ b/pom.xml @@ -1,30 +1,34 @@ - 4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.3 - + com libraryman-api 0.0.1-SNAPSHOT libraryman-api - Revolutionize book management with LibraryMan! Easily track stock, borrowers, and due dates, streamlining operations for schools, companies, and libraries worldwide, ensuring efficient and organized book lending. - + Revolutionize book management with LibraryMan! Easily track + stock, borrowers, and due dates, streamlining operations for schools, + companies, and libraries worldwide, ensuring efficient and organized + book lending. + - + - + - - - - + + + + 17 @@ -96,6 +100,11 @@ spring-security-test test + + org.springframework.security + spring-security-oauth2-client + + diff --git a/src/main/java/com/libraryman_api/book/BookController.java b/src/main/java/com/libraryman_api/book/BookController.java index 778f7c4..a071d7d 100644 --- a/src/main/java/com/libraryman_api/book/BookController.java +++ b/src/main/java/com/libraryman_api/book/BookController.java @@ -3,6 +3,7 @@ import com.libraryman_api.exception.ResourceNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -51,6 +52,7 @@ public ResponseEntity getBookById(@PathVariable int id) { * @return the added {@link Book} object. */ @PostMapping + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public Book addBook(@RequestBody Book book) { return bookService.addBook(book); } @@ -63,6 +65,7 @@ public Book addBook(@RequestBody Book book) { * @return the updated {@link Book} object. */ @PutMapping("/{id}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public Book updateBook(@PathVariable int id, @RequestBody Book bookDetails) { return bookService.updateBook(id, bookDetails); } @@ -73,6 +76,7 @@ public Book updateBook(@PathVariable int id, @RequestBody Book bookDetails) { * @param id the ID of the book to delete. */ @DeleteMapping("/{id}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public void deleteBook(@PathVariable int id) { bookService.deleteBook(id); } diff --git a/src/main/java/com/libraryman_api/borrowing/BorrowingController.java b/src/main/java/com/libraryman_api/borrowing/BorrowingController.java index e76ae53..042dd26 100644 --- a/src/main/java/com/libraryman_api/borrowing/BorrowingController.java +++ b/src/main/java/com/libraryman_api/borrowing/BorrowingController.java @@ -1,6 +1,8 @@ package com.libraryman_api.borrowing; import com.libraryman_api.exception.ResourceNotFoundException; + +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -31,6 +33,7 @@ public BorrowingController(BorrowingService borrowingService) { * @return a list of {@link Borrowings} objects representing all borrowings. */ @GetMapping + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public List getAllBorrowings() { return borrowingService.getAllBorrowings(); } @@ -75,6 +78,7 @@ public String payFine(@PathVariable int id) { * @return a list of {@link Borrowings} objects representing the member's borrowings. */ @GetMapping("member/{memberId}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public List getAllBorrowingsOfAMember(@PathVariable int memberId) { return borrowingService.getAllBorrowingsOfMember(memberId); } @@ -87,6 +91,7 @@ public List getAllBorrowingsOfAMember(@PathVariable int memberId) { * @throws ResourceNotFoundException if the borrowing record with the specified ID is not found. */ @GetMapping("{borrowingId}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public Borrowings getBorrowingById(@PathVariable int borrowingId) { return borrowingService.getBorrowingById(borrowingId) .orElseThrow(() -> new ResourceNotFoundException("Borrowing not found")); diff --git a/src/main/java/com/libraryman_api/member/MemberController.java b/src/main/java/com/libraryman_api/member/MemberController.java index 246589c..8a1c750 100644 --- a/src/main/java/com/libraryman_api/member/MemberController.java +++ b/src/main/java/com/libraryman_api/member/MemberController.java @@ -2,6 +2,7 @@ import com.libraryman_api.exception.ResourceNotFoundException; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -31,6 +32,7 @@ public MemberController(MemberService memberService) { * @return a list of {@link Members} representing all members in the library */ @GetMapping + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public List getAllMembers() { return memberService.getAllMembers(); } @@ -43,6 +45,7 @@ public List getAllMembers() { * @return a {@link ResponseEntity} containing the found {@link Members} object */ @GetMapping("/{id}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public ResponseEntity getMemberById(@PathVariable int id) { return memberService.getMemberById(id) .map(ResponseEntity::ok) @@ -80,6 +83,7 @@ public Members updateMember(@PathVariable int id, @RequestBody Members memberDet * @param id the ID of the member to delete */ @DeleteMapping("/{id}") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") public void deleteMember(@PathVariable int id) { memberService.deleteMember(id); } diff --git a/src/main/java/com/libraryman_api/member/Members.java b/src/main/java/com/libraryman_api/member/Members.java index ba222f5..591eeef 100644 --- a/src/main/java/com/libraryman_api/member/Members.java +++ b/src/main/java/com/libraryman_api/member/Members.java @@ -26,6 +26,9 @@ public class Members implements UserDetails{ @Column(nullable = false) private String name; + @Column(name = "username") + private String username; + @Column(unique = true, nullable = false) private String email; @@ -39,8 +42,7 @@ public class Members implements UserDetails{ @Column(name = "membership_date") private Date membershipDate; - @Column(name = "username") - private String username; + public Members() { @@ -109,7 +111,7 @@ public void setUsername(String username) { @Override public Collection getAuthorities() { // TODO Auto-generated method stub - return Collections.singletonList(new SimpleGrantedAuthority(role.name())); + return Collections.singletonList(new SimpleGrantedAuthority("ROLE_"+role.name())); } } diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java b/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java index c8fdbe4..b9667b8 100644 --- a/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java @@ -19,12 +19,15 @@ @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { - - @Autowired - JwtAuthenticationHelper jwtHelper; - @Autowired - UserDetailsService userDetailsService; + private JwtAuthenticationHelper jwtHelper; + + private UserDetailsService userDetailsService; + + public JwtAuthenticationFilter(JwtAuthenticationHelper jwtHelper,UserDetailsService userDetailsService) { + this.jwtHelper=jwtHelper; + this.userDetailsService=userDetailsService; + } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java b/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java index 9e95e4c..d7045e7 100644 --- a/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java +++ b/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java @@ -17,7 +17,7 @@ public class JwtAuthenticationHelper { private static final long JWT_TOKEN_VALIDITY=60*60; - private String secret="thisisacodingninjasdemonstrationforsecretkeyinspringsecurityjsonwebtokenauthentication"; + private String secret="thisisalibrarymanapisecuritysignatureforsecretkeyinspringsecurityjsonwebtokenauthentication"; public String getUsernameFromToken(String token) { String username=getClaimsFromToken(token).getSubject(); return username; diff --git a/src/main/java/com/libraryman_api/security/LoginController.java b/src/main/java/com/libraryman_api/security/LoginController.java index 27349de..cfe2cb8 100644 --- a/src/main/java/com/libraryman_api/security/LoginController.java +++ b/src/main/java/com/libraryman_api/security/LoginController.java @@ -1,20 +1,39 @@ package com.libraryman_api.security; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.security.Principal; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; @RestController public class LoginController { - @GetMapping("/api/ajay") - public String login(Principal principal) { - System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - System.out.println("Principal Name: " + principal.getName()); - System.out.println("Principal: " + principal); + private final LoginService loginService; - return "Hello World"; + public LoginController(LoginService loginService) { + this.loginService = loginService; } + @PostMapping("/api/login") + public ResponseEntity login(@RequestBody LoginRequest loginRequest, HttpServletResponse response) { + LoginResponse loginResponse = loginService.login(loginRequest); + + if (loginResponse != null) { + setAuthCookie(response); + return new ResponseEntity<>(loginResponse, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } + } + + private void setAuthCookie(HttpServletResponse response) { + Cookie cookie = new Cookie("LibraryManCookie", "libraryman_cookie"); + cookie.setMaxAge(3600); // (3600 seconds) + cookie.setPath("/"); + response.addCookie(cookie); + } } diff --git a/src/main/java/com/libraryman_api/security/LoginService.java b/src/main/java/com/libraryman_api/security/LoginService.java index 020c5a5..07690af 100644 --- a/src/main/java/com/libraryman_api/security/LoginService.java +++ b/src/main/java/com/libraryman_api/security/LoginService.java @@ -1,7 +1,5 @@ package com.libraryman_api.security; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -15,17 +13,20 @@ @Service public class LoginService { - @Autowired - AuthenticationManager authenticationManager; + private AuthenticationManager authenticationManager; + + private UserDetailsService userDetailsService; - @Autowired - UserDetailsService userDetailsService; + private JwtAuthenticationHelper jwtHelper; - @Autowired - JwtAuthenticationHelper jwtHelper; + private MemberRepository memberRepository; - @Autowired - MemberRepository memberRepository; + public LoginService(AuthenticationManager authenticationManager,UserDetailsService userDetailsService,JwtAuthenticationHelper jwtHelper,MemberRepository memberRepository) { + this.authenticationManager=authenticationManager; + this.userDetailsService=userDetailsService; + this.jwtHelper=jwtHelper; + this.memberRepository=memberRepository; + } public LoginResponse login(LoginRequest loginRequest) { Authenticate(loginRequest.getUsername(), loginRequest.getPassword()); diff --git a/src/main/java/com/libraryman_api/security/LogoutController.java b/src/main/java/com/libraryman_api/security/LogoutController.java new file mode 100644 index 0000000..0f2ddd3 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/LogoutController.java @@ -0,0 +1,34 @@ +package com.libraryman_api.security; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class LogoutController { + + @PostMapping("/api/logout") + public ResponseEntity logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + if (authentication != null) { + new SecurityContextLogoutHandler().logout(request, response, authentication); + } + removeAuthCookie(response); + + return ResponseEntity.ok("Successfully logged out."); + } + + private void removeAuthCookie(HttpServletResponse response) { + Cookie cookie = new Cookie("LibraryManCookie", null); + cookie.setMaxAge(0); + cookie.setPath("/"); + cookie.setHttpOnly(true); + cookie.setSecure(true); + response.addCookie(cookie); + } +} diff --git a/src/main/java/com/libraryman_api/security/SignupController.java b/src/main/java/com/libraryman_api/security/SignupController.java index 68584e1..78e3844 100644 --- a/src/main/java/com/libraryman_api/security/SignupController.java +++ b/src/main/java/com/libraryman_api/security/SignupController.java @@ -1,4 +1,25 @@ package com.libraryman_api.security; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.libraryman_api.member.Members; + + +@RestController public class SignupController { + + private SignupService signupService; + public SignupController(SignupService signupService) { + this.signupService=signupService; + } + + @PostMapping("/api/signup") + public void signup(@RequestBody Members members) { + this.signupService.signup(members); + + } } diff --git a/src/main/java/com/libraryman_api/security/SignupService.java b/src/main/java/com/libraryman_api/security/SignupService.java index df30b7c..de584a9 100644 --- a/src/main/java/com/libraryman_api/security/SignupService.java +++ b/src/main/java/com/libraryman_api/security/SignupService.java @@ -3,7 +3,7 @@ import java.util.Date; import java.util.Optional; -import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.stereotype.Service; @@ -14,11 +14,14 @@ @Service public class SignupService { - @Autowired - MemberRepository memberRepository; + private MemberRepository memberRepository; + + private PasswordEncoder passwordEncoder; - @Autowired - PasswordEncoder passwordEncoder; + public SignupService(MemberRepository memberRepository,PasswordEncoder passwordEncoder) { + this.memberRepository=memberRepository; + this.passwordEncoder=passwordEncoder; + } public void signup(Members members) { Optional memberOptId=memberRepository.findById(members.getMemberId()); Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); diff --git a/src/main/java/com/libraryman_api/security/WebConfiguration.java b/src/main/java/com/libraryman_api/security/WebConfiguration.java index 19f971d..821f175 100644 --- a/src/main/java/com/libraryman_api/security/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/WebConfiguration.java @@ -2,9 +2,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; + import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 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; @@ -14,16 +15,19 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; - - -import static com.libraryman_api.member.Role.ADMIN; import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; @Configuration @EnableWebSecurity(debug = true) // Do not use (debug=true) in a production system! as this contain sensitive information. +@EnableMethodSecurity(prePostEnabled = true) public class WebConfiguration { + private JwtAuthenticationFilter jwtFilter; + + public WebConfiguration(JwtAuthenticationFilter jwtFilter) { + this.jwtFilter=jwtFilter; + } @Bean public SecurityFilterChain web(HttpSecurity http) throws Exception { http @@ -31,11 +35,20 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { .authorizeHttpRequests((request) -> request // make sure it is in order to access the proper Url - .requestMatchers("/signup").permitAll() - .requestMatchers("/login").permitAll() + .requestMatchers("/api/signup").permitAll() + .requestMatchers("/api/login").permitAll() + .requestMatchers("/api/logout").permitAll() + .anyRequest().authenticated() ) -// .sessionManagement(session -> session.sessionCreationPolicy(STATELESS)) + .logout(logout->logout + .deleteCookies("LibraryManCookie")) + .sessionManagement(session -> session.sessionCreationPolicy(STATELESS)) .formLogin(withDefaults()); + + http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) + .httpBasic(httpBasic -> {}); + + http.oauth2Login(withDefaults()); return http.build(); } From 3f5523931bc4cc17c9712efe42b57f3e4fb7a85f Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 11 Oct 2024 20:37:26 +0530 Subject: [PATCH 6/9] Implemented Login and Logout Functionality --- .../security/SignupService.java | 44 ---------- .../{ => config}/PasswordEncoder.java | 2 +- .../{ => config}/WebConfiguration.java | 7 +- .../{ => controllers}/LoginController.java | 6 +- .../{ => controllers}/LogoutController.java | 2 +- .../{ => controllers}/SignupController.java | 11 ++- .../{ => jwt}/JwtAuthenticationFilter.java | 2 +- .../{ => jwt}/JwtAuthenticationHelper.java | 6 +- .../security/{ => model}/LoginRequest.java | 2 +- .../security/{ => model}/LoginResponse.java | 2 +- .../CustomUserDetailsService.java | 2 +- .../security/{ => services}/LoginService.java | 5 +- .../security/services/SignupService.java | 86 +++++++++++++++++++ src/main/resources/application.properties | 3 +- 14 files changed, 123 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/com/libraryman_api/security/SignupService.java rename src/main/java/com/libraryman_api/security/{ => config}/PasswordEncoder.java (88%) rename src/main/java/com/libraryman_api/security/{ => config}/WebConfiguration.java (93%) rename src/main/java/com/libraryman_api/security/{ => controllers}/LoginController.java (85%) rename src/main/java/com/libraryman_api/security/{ => controllers}/LogoutController.java (96%) rename src/main/java/com/libraryman_api/security/{ => controllers}/SignupController.java (61%) rename src/main/java/com/libraryman_api/security/{ => jwt}/JwtAuthenticationFilter.java (98%) rename src/main/java/com/libraryman_api/security/{ => jwt}/JwtAuthenticationHelper.java (89%) rename src/main/java/com/libraryman_api/security/{ => model}/LoginRequest.java (89%) rename src/main/java/com/libraryman_api/security/{ => model}/LoginResponse.java (84%) rename src/main/java/com/libraryman_api/security/{ => services}/CustomUserDetailsService.java (94%) rename src/main/java/com/libraryman_api/security/{ => services}/LoginService.java (88%) create mode 100644 src/main/java/com/libraryman_api/security/services/SignupService.java diff --git a/src/main/java/com/libraryman_api/security/SignupService.java b/src/main/java/com/libraryman_api/security/SignupService.java deleted file mode 100644 index de584a9..0000000 --- a/src/main/java/com/libraryman_api/security/SignupService.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.libraryman_api.security; - -import java.util.Date; -import java.util.Optional; - - -import org.springframework.stereotype.Service; - - -import com.libraryman_api.exception.ResourceNotFoundException; -import com.libraryman_api.member.MemberRepository; -import com.libraryman_api.member.Members; - -@Service -public class SignupService { - - private MemberRepository memberRepository; - - private PasswordEncoder passwordEncoder; - - public SignupService(MemberRepository memberRepository,PasswordEncoder passwordEncoder) { - this.memberRepository=memberRepository; - this.passwordEncoder=passwordEncoder; - } - public void signup(Members members) { - Optional memberOptId=memberRepository.findById(members.getMemberId()); - Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); - if(memberOptId.isPresent()) { - throw new ResourceNotFoundException("User already Exists"); - } - if(memberOptUsername.isPresent()) { - throw new ResourceNotFoundException("User already Exists"); - } - String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); - Members new_members=new Members(); - new_members.setEmail(members.getEmail()); - new_members.setName(members.getName()); - new_members.setPassword(encoded_password); - new_members.setRole(members.getRole()); - new_members.setMembershipDate(new Date()); - new_members.setUsername(members.getUsername()); - memberRepository.save(new_members); - } -} diff --git a/src/main/java/com/libraryman_api/security/PasswordEncoder.java b/src/main/java/com/libraryman_api/security/config/PasswordEncoder.java similarity index 88% rename from src/main/java/com/libraryman_api/security/PasswordEncoder.java rename to src/main/java/com/libraryman_api/security/config/PasswordEncoder.java index 31a6fa5..4d2da03 100644 --- a/src/main/java/com/libraryman_api/security/PasswordEncoder.java +++ b/src/main/java/com/libraryman_api/security/config/PasswordEncoder.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/libraryman_api/security/WebConfiguration.java b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java similarity index 93% rename from src/main/java/com/libraryman_api/security/WebConfiguration.java rename to src/main/java/com/libraryman_api/security/config/WebConfiguration.java index 821f175..a6a3883 100644 --- a/src/main/java/com/libraryman_api/security/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,6 +15,9 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; + +import com.libraryman_api.security.jwt.JwtAuthenticationFilter; + import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; @@ -36,6 +39,8 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { // make sure it is in order to access the proper Url .requestMatchers("/api/signup").permitAll() + .requestMatchers("/api/signup/admin").permitAll() + .requestMatchers("/api/signup/librarian").permitAll() .requestMatchers("/api/login").permitAll() .requestMatchers("/api/logout").permitAll() .anyRequest().authenticated() diff --git a/src/main/java/com/libraryman_api/security/LoginController.java b/src/main/java/com/libraryman_api/security/controllers/LoginController.java similarity index 85% rename from src/main/java/com/libraryman_api/security/LoginController.java rename to src/main/java/com/libraryman_api/security/controllers/LoginController.java index cfe2cb8..aed0c1e 100644 --- a/src/main/java/com/libraryman_api/security/LoginController.java +++ b/src/main/java/com/libraryman_api/security/controllers/LoginController.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.controllers; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -6,6 +6,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import com.libraryman_api.security.model.LoginRequest; +import com.libraryman_api.security.model.LoginResponse; +import com.libraryman_api.security.services.LoginService; + import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletResponse; diff --git a/src/main/java/com/libraryman_api/security/LogoutController.java b/src/main/java/com/libraryman_api/security/controllers/LogoutController.java similarity index 96% rename from src/main/java/com/libraryman_api/security/LogoutController.java rename to src/main/java/com/libraryman_api/security/controllers/LogoutController.java index 0f2ddd3..20d4a92 100644 --- a/src/main/java/com/libraryman_api/security/LogoutController.java +++ b/src/main/java/com/libraryman_api/security/controllers/LogoutController.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.controllers; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/libraryman_api/security/SignupController.java b/src/main/java/com/libraryman_api/security/controllers/SignupController.java similarity index 61% rename from src/main/java/com/libraryman_api/security/SignupController.java rename to src/main/java/com/libraryman_api/security/controllers/SignupController.java index 78e3844..930e309 100644 --- a/src/main/java/com/libraryman_api/security/SignupController.java +++ b/src/main/java/com/libraryman_api/security/controllers/SignupController.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.controllers; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.RestController; import com.libraryman_api.member.Members; +import com.libraryman_api.security.services.SignupService; @RestController @@ -22,4 +23,12 @@ public void signup(@RequestBody Members members) { this.signupService.signup(members); } + @PostMapping("/api/signup/admin") + public void signupAdmin(@RequestBody Members members) { + this.signupService.signupAdmin(members); + } + @PostMapping("/api/signup/librarian") + public void signupLibrarian(@RequestBody Members members) { + this.signupService.signupLibrarian(members); + } } diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java b/src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationFilter.java similarity index 98% rename from src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java rename to src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationFilter.java index b9667b8..875779b 100644 --- a/src/main/java/com/libraryman_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationFilter.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.jwt; import java.io.IOException; diff --git a/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java b/src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationHelper.java similarity index 89% rename from src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java rename to src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationHelper.java index d7045e7..b44e446 100644 --- a/src/main/java/com/libraryman_api/security/JwtAuthenticationHelper.java +++ b/src/main/java/com/libraryman_api/security/jwt/JwtAuthenticationHelper.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.jwt; import java.util.Date; import java.util.HashMap; @@ -6,6 +6,7 @@ import javax.crypto.spec.SecretKeySpec; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; @@ -17,7 +18,8 @@ public class JwtAuthenticationHelper { private static final long JWT_TOKEN_VALIDITY=60*60; - private String secret="thisisalibrarymanapisecuritysignatureforsecretkeyinspringsecurityjsonwebtokenauthentication"; + @Value("${jwt.secretKey}") + private String secret; public String getUsernameFromToken(String token) { String username=getClaimsFromToken(token).getSubject(); return username; diff --git a/src/main/java/com/libraryman_api/security/LoginRequest.java b/src/main/java/com/libraryman_api/security/model/LoginRequest.java similarity index 89% rename from src/main/java/com/libraryman_api/security/LoginRequest.java rename to src/main/java/com/libraryman_api/security/model/LoginRequest.java index 16e70b9..e77d1cd 100644 --- a/src/main/java/com/libraryman_api/security/LoginRequest.java +++ b/src/main/java/com/libraryman_api/security/model/LoginRequest.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.model; public class LoginRequest { diff --git a/src/main/java/com/libraryman_api/security/LoginResponse.java b/src/main/java/com/libraryman_api/security/model/LoginResponse.java similarity index 84% rename from src/main/java/com/libraryman_api/security/LoginResponse.java rename to src/main/java/com/libraryman_api/security/model/LoginResponse.java index 9488d64..2b53d41 100644 --- a/src/main/java/com/libraryman_api/security/LoginResponse.java +++ b/src/main/java/com/libraryman_api/security/model/LoginResponse.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.model; public class LoginResponse { diff --git a/src/main/java/com/libraryman_api/security/CustomUserDetailsService.java b/src/main/java/com/libraryman_api/security/services/CustomUserDetailsService.java similarity index 94% rename from src/main/java/com/libraryman_api/security/CustomUserDetailsService.java rename to src/main/java/com/libraryman_api/security/services/CustomUserDetailsService.java index ace26e7..2c66c82 100644 --- a/src/main/java/com/libraryman_api/security/CustomUserDetailsService.java +++ b/src/main/java/com/libraryman_api/security/services/CustomUserDetailsService.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; diff --git a/src/main/java/com/libraryman_api/security/LoginService.java b/src/main/java/com/libraryman_api/security/services/LoginService.java similarity index 88% rename from src/main/java/com/libraryman_api/security/LoginService.java rename to src/main/java/com/libraryman_api/security/services/LoginService.java index 07690af..c255c4e 100644 --- a/src/main/java/com/libraryman_api/security/LoginService.java +++ b/src/main/java/com/libraryman_api/security/services/LoginService.java @@ -1,4 +1,4 @@ -package com.libraryman_api.security; +package com.libraryman_api.security.services; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; @@ -8,6 +8,9 @@ import org.springframework.stereotype.Service; import com.libraryman_api.member.MemberRepository; +import com.libraryman_api.security.jwt.JwtAuthenticationHelper; +import com.libraryman_api.security.model.LoginRequest; +import com.libraryman_api.security.model.LoginResponse; @Service diff --git a/src/main/java/com/libraryman_api/security/services/SignupService.java b/src/main/java/com/libraryman_api/security/services/SignupService.java new file mode 100644 index 0000000..f00a263 --- /dev/null +++ b/src/main/java/com/libraryman_api/security/services/SignupService.java @@ -0,0 +1,86 @@ +package com.libraryman_api.security.services; + +import java.util.Date; +import java.util.Optional; + + +import org.springframework.stereotype.Service; + + +import com.libraryman_api.exception.ResourceNotFoundException; +import com.libraryman_api.member.MemberRepository; +import com.libraryman_api.member.Members; +import com.libraryman_api.member.Role; +import com.libraryman_api.security.config.PasswordEncoder; + +@Service +public class SignupService { + + private MemberRepository memberRepository; + + private PasswordEncoder passwordEncoder; + + public SignupService(MemberRepository memberRepository,PasswordEncoder passwordEncoder) { + this.memberRepository=memberRepository; + this.passwordEncoder=passwordEncoder; + } + public void signup(Members members) { + Optional memberOptId=memberRepository.findById(members.getMemberId()); + Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); + if(memberOptId.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + if(memberOptUsername.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); + Members new_members=new Members(); + new_members.setEmail(members.getEmail()); + new_members.setName(members.getName()); + new_members.setPassword(encoded_password); + new_members.setRole(Role.USER); + new_members.setMembershipDate(new Date()); + new_members.setUsername(members.getUsername()); + memberRepository.save(new_members); + } + + public void signupAdmin(Members members) { + Optional memberOptId=memberRepository.findById(members.getMemberId()); + Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); + if(memberOptId.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + if(memberOptUsername.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); + Members new_members=new Members(); + new_members.setEmail(members.getEmail()); + new_members.setName(members.getName()); + new_members.setPassword(encoded_password); + new_members.setRole(Role.ADMIN); + new_members.setMembershipDate(new Date()); + new_members.setUsername(members.getUsername()); + memberRepository.save(new_members); + + } + public void signupLibrarian(Members members) { + Optional memberOptId=memberRepository.findById(members.getMemberId()); + Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); + if(memberOptId.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + if(memberOptUsername.isPresent()) { + throw new ResourceNotFoundException("User already Exists"); + } + String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); + Members new_members=new Members(); + new_members.setEmail(members.getEmail()); + new_members.setName(members.getName()); + new_members.setPassword(encoded_password); + new_members.setRole(Role.LIBRARIAN); + new_members.setMembershipDate(new Date()); + new_members.setUsername(members.getUsername()); + memberRepository.save(new_members); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index eeefb5c..0daab8c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,3 @@ spring.application.name=libraryman-api -spring.profiles.active=${ENV:dev} \ No newline at end of file +spring.profiles.active=${ENV:production} +jwt.secretKey=${YOUR_JWT_SECRET_KEY} \ No newline at end of file From 57ae1cf0c1d9d654cc9feb1e7ef6a1c6b0913692 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 11 Oct 2024 20:38:22 +0530 Subject: [PATCH 7/9] Implemented Login and Logout Functionality --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0daab8c..3fce839 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,3 @@ spring.application.name=libraryman-api -spring.profiles.active=${ENV:production} +spring.profiles.active=${ENV:dev} jwt.secretKey=${YOUR_JWT_SECRET_KEY} \ No newline at end of file From 4cc8056b6f1ab5d3a6c33a0009ef3a605b6ada8b Mon Sep 17 00:00:00 2001 From: Rishabh Date: Sat, 12 Oct 2024 09:39:43 +0530 Subject: [PATCH 8/9] Implemented Login and Logout Functionality --- .../security/config/WebConfiguration.java | 4 ++-- .../security/controllers/SignupController.java | 15 +++++++-------- .../security/services/SignupService.java | 18 +++++++++++++++--- src/main/resources/application.properties | 4 +++- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java index a6a3883..75c966d 100644 --- a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java @@ -39,8 +39,8 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { // make sure it is in order to access the proper Url .requestMatchers("/api/signup").permitAll() - .requestMatchers("/api/signup/admin").permitAll() - .requestMatchers("/api/signup/librarian").permitAll() + .requestMatchers("/api/signup/admin/{secretKey}").permitAll() + .requestMatchers("/api/signup/librarian/{secretKey}").permitAll() .requestMatchers("/api/login").permitAll() .requestMatchers("/api/logout").permitAll() .anyRequest().authenticated() diff --git a/src/main/java/com/libraryman_api/security/controllers/SignupController.java b/src/main/java/com/libraryman_api/security/controllers/SignupController.java index 930e309..2d6244c 100644 --- a/src/main/java/com/libraryman_api/security/controllers/SignupController.java +++ b/src/main/java/com/libraryman_api/security/controllers/SignupController.java @@ -1,7 +1,6 @@ package com.libraryman_api.security.controllers; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -23,12 +22,12 @@ public void signup(@RequestBody Members members) { this.signupService.signup(members); } - @PostMapping("/api/signup/admin") - public void signupAdmin(@RequestBody Members members) { - this.signupService.signupAdmin(members); + @PostMapping("/api/signup/admin/{secretKey}") + public void signupAdmin(@RequestBody Members members,@PathVariable String secretKey) { + this.signupService.signupAdmin(members,secretKey); } - @PostMapping("/api/signup/librarian") - public void signupLibrarian(@RequestBody Members members) { - this.signupService.signupLibrarian(members); + @PostMapping("/api/signup/librarian/{secretKey}") + public void signupLibrarian(@RequestBody Members members,@PathVariable String secretKey) { + this.signupService.signupLibrarian(members,secretKey); } } diff --git a/src/main/java/com/libraryman_api/security/services/SignupService.java b/src/main/java/com/libraryman_api/security/services/SignupService.java index f00a263..c5f928f 100644 --- a/src/main/java/com/libraryman_api/security/services/SignupService.java +++ b/src/main/java/com/libraryman_api/security/services/SignupService.java @@ -3,7 +3,7 @@ import java.util.Date; import java.util.Optional; - +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -20,6 +20,12 @@ public class SignupService { private PasswordEncoder passwordEncoder; + @Value("${admin.secretKey}") + private String adminSecretKey; + + @Value("${librarian.secretKey}") + private String librarianSecretKey; + public SignupService(MemberRepository memberRepository,PasswordEncoder passwordEncoder) { this.memberRepository=memberRepository; this.passwordEncoder=passwordEncoder; @@ -44,7 +50,7 @@ public void signup(Members members) { memberRepository.save(new_members); } - public void signupAdmin(Members members) { + public void signupAdmin(Members members,String secretKey) { Optional memberOptId=memberRepository.findById(members.getMemberId()); Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); if(memberOptId.isPresent()) { @@ -53,6 +59,9 @@ public void signupAdmin(Members members) { if(memberOptUsername.isPresent()) { throw new ResourceNotFoundException("User already Exists"); } + if(!adminSecretKey.equals(secretKey)) { + throw new ResourceNotFoundException("Secret Key does not match"); + } String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); Members new_members=new Members(); new_members.setEmail(members.getEmail()); @@ -64,7 +73,7 @@ public void signupAdmin(Members members) { memberRepository.save(new_members); } - public void signupLibrarian(Members members) { + public void signupLibrarian(Members members,String secretKey) { Optional memberOptId=memberRepository.findById(members.getMemberId()); Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); if(memberOptId.isPresent()) { @@ -73,6 +82,9 @@ public void signupLibrarian(Members members) { if(memberOptUsername.isPresent()) { throw new ResourceNotFoundException("User already Exists"); } + if(!librarianSecretKey.equals(secretKey)) { + throw new ResourceNotFoundException("secret key does not match"); + } String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); Members new_members=new Members(); new_members.setEmail(members.getEmail()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3fce839..08f31b7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,5 @@ spring.application.name=libraryman-api spring.profiles.active=${ENV:dev} -jwt.secretKey=${YOUR_JWT_SECRET_KEY} \ No newline at end of file +jwt.secretKey=${YOUR_JWT_SECRET_KEY} +admin.secretKey=${ADMIN_SECRET_KEY} +librarian.secretKey=${LIBRARIAN_SECRET_KEY} \ No newline at end of file From 9e813c15b7fd2cc380abd1de842c160bbeb963a8 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Sat, 12 Oct 2024 22:09:03 +0530 Subject: [PATCH 9/9] Implemented Login and Logout Functionality --- .../security/config/WebConfiguration.java | 2 -- .../security/controllers/SignupController.java | 15 +++++++++------ .../security/services/SignupService.java | 16 +++------------- src/main/resources/application.properties | 2 -- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java index 75c966d..47d2d60 100644 --- a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java +++ b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java @@ -39,8 +39,6 @@ public SecurityFilterChain web(HttpSecurity http) throws Exception { // make sure it is in order to access the proper Url .requestMatchers("/api/signup").permitAll() - .requestMatchers("/api/signup/admin/{secretKey}").permitAll() - .requestMatchers("/api/signup/librarian/{secretKey}").permitAll() .requestMatchers("/api/login").permitAll() .requestMatchers("/api/logout").permitAll() .anyRequest().authenticated() diff --git a/src/main/java/com/libraryman_api/security/controllers/SignupController.java b/src/main/java/com/libraryman_api/security/controllers/SignupController.java index 2d6244c..a1f6891 100644 --- a/src/main/java/com/libraryman_api/security/controllers/SignupController.java +++ b/src/main/java/com/libraryman_api/security/controllers/SignupController.java @@ -1,5 +1,6 @@ package com.libraryman_api.security.controllers; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -22,12 +23,14 @@ public void signup(@RequestBody Members members) { this.signupService.signup(members); } - @PostMapping("/api/signup/admin/{secretKey}") - public void signupAdmin(@RequestBody Members members,@PathVariable String secretKey) { - this.signupService.signupAdmin(members,secretKey); + @PostMapping("/api/signup/admin") + @PreAuthorize("hasRole('ADMIN')") + public void signupAdmin(@RequestBody Members members) { + this.signupService.signupAdmin(members); } - @PostMapping("/api/signup/librarian/{secretKey}") - public void signupLibrarian(@RequestBody Members members,@PathVariable String secretKey) { - this.signupService.signupLibrarian(members,secretKey); + @PostMapping("/api/signup/librarian") + @PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')") + public void signupLibrarian(@RequestBody Members members) { + this.signupService.signupLibrarian(members); } } diff --git a/src/main/java/com/libraryman_api/security/services/SignupService.java b/src/main/java/com/libraryman_api/security/services/SignupService.java index c5f928f..33ff122 100644 --- a/src/main/java/com/libraryman_api/security/services/SignupService.java +++ b/src/main/java/com/libraryman_api/security/services/SignupService.java @@ -20,11 +20,6 @@ public class SignupService { private PasswordEncoder passwordEncoder; - @Value("${admin.secretKey}") - private String adminSecretKey; - - @Value("${librarian.secretKey}") - private String librarianSecretKey; public SignupService(MemberRepository memberRepository,PasswordEncoder passwordEncoder) { this.memberRepository=memberRepository; @@ -50,7 +45,7 @@ public void signup(Members members) { memberRepository.save(new_members); } - public void signupAdmin(Members members,String secretKey) { + public void signupAdmin(Members members) { Optional memberOptId=memberRepository.findById(members.getMemberId()); Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); if(memberOptId.isPresent()) { @@ -59,9 +54,7 @@ public void signupAdmin(Members members,String secretKey) { if(memberOptUsername.isPresent()) { throw new ResourceNotFoundException("User already Exists"); } - if(!adminSecretKey.equals(secretKey)) { - throw new ResourceNotFoundException("Secret Key does not match"); - } + String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); Members new_members=new Members(); new_members.setEmail(members.getEmail()); @@ -73,7 +66,7 @@ public void signupAdmin(Members members,String secretKey) { memberRepository.save(new_members); } - public void signupLibrarian(Members members,String secretKey) { + public void signupLibrarian(Members members) { Optional memberOptId=memberRepository.findById(members.getMemberId()); Optional memberOptUsername=memberRepository.findByUsername(members.getUsername()); if(memberOptId.isPresent()) { @@ -82,9 +75,6 @@ public void signupLibrarian(Members members,String secretKey) { if(memberOptUsername.isPresent()) { throw new ResourceNotFoundException("User already Exists"); } - if(!librarianSecretKey.equals(secretKey)) { - throw new ResourceNotFoundException("secret key does not match"); - } String encoded_password=passwordEncoder.bCryptPasswordEncoder().encode(members.getPassword()); Members new_members=new Members(); new_members.setEmail(members.getEmail()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 08f31b7..004aed8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,3 @@ spring.application.name=libraryman-api spring.profiles.active=${ENV:dev} jwt.secretKey=${YOUR_JWT_SECRET_KEY} -admin.secretKey=${ADMIN_SECRET_KEY} -librarian.secretKey=${LIBRARIAN_SECRET_KEY} \ No newline at end of file