diff --git a/DOCS.md b/DOCS.md
new file mode 100644
index 0000000..6b33178
--- /dev/null
+++ b/DOCS.md
@@ -0,0 +1,57 @@
+# Java Web MVC Application
+
+## Description
+
+ This Spring Boot application leverages the latest Spring Security 6, JSON Web Token, and Thymeleaf dependencies. Built with an MVC architecture, the app provides a user-friendly authentication mechanism for seamless user interactions. This app offers a range of features, including Java SMTP mail for password reset, user registration, user login, user deletion, and log-out functionality. The app starts with 11 users: 1 admin, 10 users. Admin can delete users, while regular users have limited access to the dashboard.
+
+## Instruction
+
+ ### Guide to run the project:
+
+ - clone the repo
+
+ - change directory to internSathi: `cd InternSathi`
+
+ - build all jar: `./gradlew build`
+
+ - run the project with terminal command: `./gradlew bootrun`
+
+ - open your browser and type: `http://localhost:7999/internsathi/user/login`
+
+## Login with following credentials:
+
+ Admin:
+ username: am0007
+ password: password
+
+ User:
+ username: am007
+ password: password
+
+## Point to consider
+
+ This project uses SMTP mail sender functionality to send emails to user email addresses. To enable this feature, make sure to provide valid credentials for the `mail.username` and `mail.password` fields in the application properties. However, for security reasons, it is advisable not to store sensitive information like passwords directly in the properties file. Instead, securely provide the credentials to ensure the safety of your Google account. If the `mail.username` and `mail.password` fields are left empty, the app will not be able to reset user passwords. Please add the necessary configuration in the YAML file to enable this functionality.
+
+ ## Demo
+ 1. Login Page:
+ 
+
+ 2. Registration Page
+ 
+
+ 3. Reset Password Page
+ 
+
+ 4. Otp submission Page
+ 
+
+ 5. Dashboard (Admin)
+ 
+
+ 6. Dashboard (User)
+ 
+
+ 7. Reset Email
+ 
+
+
diff --git a/InternSathi/build.gradle b/InternSathi/build.gradle
index a96702d..90facad 100644
--- a/InternSathi/build.gradle
+++ b/InternSathi/build.gradle
@@ -32,6 +32,7 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
+ implementation 'org.springframework.boot:spring-boot-starter-mail:3.1.1'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/controller/HomeDashboardController.java b/InternSathi/src/main/java/internsathi/javaAssignment/controller/HomeDashboardController.java
index 2242606..de91aec 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/controller/HomeDashboardController.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/controller/HomeDashboardController.java
@@ -1,46 +1,88 @@
package internsathi.javaAssignment.controller;
-import internsathi.javaAssignment.model.UserSecurity;
+import internsathi.javaAssignment.Enum.Role;
+import internsathi.javaAssignment.entity.User;
import internsathi.javaAssignment.security.token.JwtTokenService;
+import internsathi.javaAssignment.service.UserService;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.*;
-import java.security.NoSuchAlgorithmException;
import java.security.Principal;
-import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.List;
-@RequestMapping("/internsathi/user")
+@RequestMapping("/internsathi")
@Controller
@Slf4j
public class HomeDashboardController {
private final JwtTokenService jwtTokenService;
+ private final UserService userService;
- public HomeDashboardController(JwtTokenService jwtTokenService) {
+ public HomeDashboardController(JwtTokenService jwtTokenService, UserService userService) {
this.jwtTokenService = jwtTokenService;
+ this.userService = userService;
}
- @GetMapping("/home")
- public String homePage(Model model, Authentication authentication, Principal principal) {
+ @GetMapping("/user/home")
+ public String userHomePage(Model model,
+ @RequestHeader(value = "Authorization", defaultValue = "") String authHeader,
+ Authentication authentication, Principal principal,
+ HttpServletRequest request, HttpServletResponse response) {
+
+ System.out.println(authHeader);
+ System.out.println(request.getHeader("Authorization"));
if (authentication.isAuthenticated()) {
- String loggedInUser = (String) authentication.getPrincipal();
- log.info("...{}", loggedInUser);
+ List authorities = authentication.getAuthorities()
+ .stream()
+ .map(GrantedAuthority::getAuthority)
+ .toList();
String token;
- try {
- token = jwtTokenService.generateToken(loggedInUser);
- } catch (Exception e) {
- token = "1234";
- throw new RuntimeException(e);
+ String loggedInUser = (String) authentication.getPrincipal();
+ if (request.getHeader("Authorization") == null) {
+
+ log.info("logged In: .......{}", loggedInUser);
+ try {
+
+ token = jwtTokenService.generateToken(loggedInUser);
+ model.addAttribute("token", token);
+ model.addAttribute("principal", principal.getName());
+ response.addHeader("Authorization", token);
+ log.info("token {}", token);
+
+ } catch (Exception e) {
+ token = "1234";
+ throw new RuntimeException(e);
+ }
+ }
+ if (request.getHeader("Authorization") != null) {
+ token = request.getHeader("Authorization");
+ response.addHeader("Authorization", token);
+ }
+ log.info("is Admin?...." + authorities.contains(Role.ADMIN.name()));
+ if (authorities.contains(Role.ADMIN.name())) {
+ List userList = getAllUser();
+ model.addAttribute("admin", true);
+ model.addAttribute("userList", userList);
}
- model.addAttribute("token", token);
- log.info("token {}", token);
}
- model.addAttribute("principal", principal.getName());
- return "home";
+ return "userHome";
+ }
+
+ @PostMapping("/admin/deleteUserById")
+ public String deleteUserById(Model model, @RequestParam(value = "userId", defaultValue = "0") Long userId) {
+ userService.deleteUserById(userId);
+ return "redirect:/internsathi/user/home";
+
}
+ private List getAllUser() {
+ return userService.getAllUser();
+ }
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/controller/RegisterUserController.java b/InternSathi/src/main/java/internsathi/javaAssignment/controller/RegisterUserController.java
index bf9f9b3..d3cd0d7 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/controller/RegisterUserController.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/controller/RegisterUserController.java
@@ -5,7 +5,6 @@
import internsathi.javaAssignment.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@@ -34,6 +33,7 @@ public String registerPage(Model model,
@PostMapping(value = "/registerUser")
public String registerUser(Model model, @ModelAttribute UserRegistrationDto userRegistrationDetail) {
try {
+ userRegistrationDetail.setRole("USER");
UserRegistrationResponseDto userRegistrationResponseDto = userService.registerUser(userRegistrationDetail);
if (userRegistrationResponseDto.getStatus().equals(HttpStatus.CREATED)) {
model.addAttribute("isRegistrationSuccessful", true);
@@ -44,18 +44,4 @@ public String registerUser(Model model, @ModelAttribute UserRegistrationDto user
return "redirect:/internsathi/user/registerUser?isRegistrationError=true";
}
}
-
- /*@PostMapping("/registerUser")
- public ResponseEntity registerUser(@RequestBody UserRegistrationDto userRegistrationDetail) {
- try {
- return new ResponseEntity<>(userService.registerUser(userRegistrationDetail), HttpStatus.CREATED);
- } catch (Exception e) {
- UserRegistrationResponseDto userRegistrationFailedResponse = UserRegistrationResponseDto.builder()
- .message("User registration Failed")
- .status(HttpStatus.BAD_REQUEST)
- .username(userRegistrationDetail.getUsername())
- .build();
- return new ResponseEntity<>(userRegistrationFailedResponse, HttpStatus.BAD_REQUEST);
- }
- }*/
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/controller/RestController.java b/InternSathi/src/main/java/internsathi/javaAssignment/controller/RestController.java
new file mode 100644
index 0000000..bd0630e
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/controller/RestController.java
@@ -0,0 +1,49 @@
+package internsathi.javaAssignment.controller;
+
+import internsathi.javaAssignment.dto.LoginDto;
+import internsathi.javaAssignment.security.manager.CustomAuthenticationManager;
+import internsathi.javaAssignment.security.token.JwtTokenService;
+import internsathi.javaAssignment.service.UserService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+@org.springframework.web.bind.annotation.RestController
+@RequestMapping("/internsathi/rc")
+public class RestController {
+
+ private final CustomAuthenticationManager customAuthenticationManager;
+ private final JwtTokenService jwtTokenService;
+
+ public RestController(CustomAuthenticationManager customAuthenticationManager, JwtTokenService jwtTokenService) {
+ this.customAuthenticationManager = customAuthenticationManager;
+ this.jwtTokenService = jwtTokenService;
+ }
+
+ @PostMapping("/login")
+ public ResponseEntity> loginUser(@RequestBody LoginDto loginDto) {
+ HashMap token = new HashMap<>();
+
+ Authentication authentication = customAuthenticationManager.authenticate(
+ new UsernamePasswordAuthenticationToken(
+ loginDto.getUsername(),
+ loginDto.getPassword(),
+ new ArrayList<>()
+ )
+ );
+
+ if (authentication.isAuthenticated()) {
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String access_token = jwtTokenService.generateToken((String) authentication.getPrincipal());
+ token.put("access_token", access_token);
+ }
+
+ return new ResponseEntity<>(token, HttpStatus.OK);
+ }
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/controller/UserController.java b/InternSathi/src/main/java/internsathi/javaAssignment/controller/UserController.java
index 0d307b3..99fc7c4 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/controller/UserController.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/controller/UserController.java
@@ -1,20 +1,23 @@
package internsathi.javaAssignment.controller;
+import internsathi.javaAssignment.Enum.Role;
import internsathi.javaAssignment.dto.LoginDto;
-import internsathi.javaAssignment.model.UserSecurity;
+import internsathi.javaAssignment.dto.ResetPasswordDto;
import internsathi.javaAssignment.security.token.JwtTokenService;
+import internsathi.javaAssignment.service.EmailService;
import internsathi.javaAssignment.service.UserService;
-import lombok.extern.java.Log;
+import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
-import java.security.NoSuchAlgorithmException;
-import java.security.Principal;
-import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
//@RestController
@Controller
@@ -24,10 +27,12 @@ public class UserController {
private final UserService userService;
private final JwtTokenService jwtTokenService;
+ private final EmailService emailService;
- public UserController(UserService userService, JwtTokenService jwtTokenService) {
+ public UserController(UserService userService, JwtTokenService jwtTokenService, EmailService emailService) {
this.userService = userService;
this.jwtTokenService = jwtTokenService;
+ this.emailService = emailService;
}
/*@PostMapping("/registerUser")
@@ -44,33 +49,75 @@ public ResponseEntity registerUser(@RequestBody Use
}
}*/
- @GetMapping("/login")
- public String loginPage(Model model, @RequestParam(defaultValue = "false", value = "error") boolean error) {
- model.addAttribute("login", new LoginDto());
- if (error) {
- model.addAttribute("error", true);
- }
- return "login";
+ @GetMapping("/login")
+ public String loginPage(Model model, @RequestParam(defaultValue = "false", value = "error") boolean error, @RequestParam(value = "isOtpVerified", defaultValue = "false") boolean isOtpVerified) {
+ model.addAttribute("login", new LoginDto());
+ if (error) {
+ model.addAttribute("error", true);
}
+ if (isOtpVerified) {
+ model.addAttribute("isOtpVerified", true);
+ }
+ return "login";
+ }
+
+ @PostMapping("/login")
+ public String login(Model model, Authentication authentication) {
+ List authorities = authentication.getAuthorities()
+ .stream()
+ .map(GrantedAuthority::getAuthority)
+ .toList();
+ System.out.println("...." + authorities.contains(Role.ADMIN.name()));
+ if (authentication.isAuthenticated()) {
+ return "redirect:/internsathi/user/home";
+ }
+ return "redirect:/internsathi/user/login?error=true";
+ }
+
+ @GetMapping("/resetPassword")
+ public String resetPasswordPage(Model model, @RequestParam(value = "error", defaultValue = "false") boolean error) {
+ model.addAttribute("resetPassword", new ResetPasswordDto());
+ model.addAttribute("error", error);
+ return "forgetPassword";
+ }
- @PostMapping("/login")
- public String login(Model model, Authentication authentication) {
- if (authentication.isAuthenticated()) {
- /*UserSecurity loggedInUser = (UserSecurity) authentication.getPrincipal();
- log.info("...{}", loggedInUser.user());
- String token;
- try {
- token = jwtTokenService.generateToken(loggedInUser.getUsername());
- } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
- token = "1234";
- throw new RuntimeException(e);
- }
- model.addAttribute("token", token);
- log.info("token {}", token);*/
- return "redirect:/internsathi/user/home";
- }
- System.out.println(authentication.isAuthenticated());
- return "redirect:/internsathi/user/login?error=true";
+ @PostMapping("/resetPassword")
+ public String resetPassword(Model model, @ModelAttribute ResetPasswordDto resetPassword) {
+ /*ResetPasswordDto resetPassword = (ResetPasswordDto) model.getAttribute("resetPassword");
+ assert resetPassword != null;*/
+ boolean doesUsernameAndEmailExists = userService.doesEmailAndUsernameExits(resetPassword.getUsername(), resetPassword.getEmail());
+ if (!doesUsernameAndEmailExists) {
+ model.addAttribute("error", true);
+ return "redirect:/internsathi/user/resetPassword?error=true";
+ } else {
+ model.addAttribute("success", true);
+ return "redirect:/internsathi/user/otpVerification?username=" + resetPassword.getUsername();
}
+ }
+
+ @GetMapping("/otpVerification")
+ public String OtpVerificationPage(Model model,
+ @RequestParam(value = "error", defaultValue = "false") boolean error,
+ @RequestParam("username") String username) {
+ model.addAttribute("username", username);
+ model.addAttribute("otpKey", String.class);
+ model.addAttribute("error", error);
+ return "otpVerification";
+ }
+
+ @PostMapping("/otpVerification")
+ public String verifyOtp(Model model,
+ @RequestParam("username") String username,
+ @RequestParam("password") String password,
+ String otpKey) {
+ log.info("username: {}", username);
+ System.out.println(otpKey);
+ boolean isOtpVerified = emailService.verifyOtp(otpKey, username);
+ if (isOtpVerified) {
+ userService.updatePassword(username, password);
+ return "redirect:/internsathi/user/login?isOtpVerified=true";
+ }
+ return "redirect:/internsathi/user/otpVerification?username=" + username +"&error=true";
+ }
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/dto/ResetPasswordDto.java b/InternSathi/src/main/java/internsathi/javaAssignment/dto/ResetPasswordDto.java
new file mode 100644
index 0000000..3724cfa
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/dto/ResetPasswordDto.java
@@ -0,0 +1,11 @@
+package internsathi.javaAssignment.dto;
+
+import lombok.Data;
+
+@Data
+public class ResetPasswordDto {
+
+ private String username;
+ private String email;
+ private String password;
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/entity/EmailMessage.java b/InternSathi/src/main/java/internsathi/javaAssignment/entity/EmailMessage.java
new file mode 100644
index 0000000..36ed927
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/entity/EmailMessage.java
@@ -0,0 +1,20 @@
+package internsathi.javaAssignment.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class EmailMessage {
+
+ private String mailTo;
+ public static final String EMAIL_SUBJECT = "Reset password";
+ private final String message = "Your 6-digit Otp key is sent to " + this.mailTo
+ + ". Enter your pin within a minute.\n"
+ + "Otp key: ";
+
+ public EmailMessage(String mailTo) {
+ this.mailTo = mailTo;
+ }
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/entity/Otp.java b/InternSathi/src/main/java/internsathi/javaAssignment/entity/Otp.java
new file mode 100644
index 0000000..cfc8e07
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/entity/Otp.java
@@ -0,0 +1,25 @@
+package internsathi.javaAssignment.entity;
+
+import jakarta.persistence.*;
+import lombok.Builder;
+import lombok.Data;
+
+@Entity
+@Table(name = "tb_otp")
+@Data
+public class Otp {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ private String username;
+ private String otpKey;
+
+ public Otp(String username, String otpKey) {
+ this.username = username;
+ this.otpKey = otpKey;
+ }
+
+ public Otp() {
+ }
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/entity/User.java b/InternSathi/src/main/java/internsathi/javaAssignment/entity/User.java
index c1c27fa..5c52222 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/entity/User.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/entity/User.java
@@ -22,6 +22,7 @@ public class User {
private Long id;
private String name;
+ @Column(unique = true)
private String username;
private String password;
private String email;
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/exception/UserRegistrationFailedException.java b/InternSathi/src/main/java/internsathi/javaAssignment/exception/UserRegistrationFailedException.java
deleted file mode 100644
index 4165c27..0000000
--- a/InternSathi/src/main/java/internsathi/javaAssignment/exception/UserRegistrationFailedException.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package internsathi.javaAssignment.exception;
-
-public class UserRegistrationFailedException {
-}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/mapper/UserMapper.java b/InternSathi/src/main/java/internsathi/javaAssignment/mapper/UserMapper.java
index 87b1f35..7caad64 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/mapper/UserMapper.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/mapper/UserMapper.java
@@ -48,6 +48,19 @@ default User conversionFromRegistrationDtoToUser(UserRegistrationDto registratio
.password(registrationDto.getPassword())
.role(Role.USER.name())
.build();
+ }
+
+ default User conversionFromRegistrationDtoToAdminUser(UserRegistrationDto registrationDto) {
+ return User.builder()
+ .username(registrationDto.getUsername())
+ .name(registrationDto.getName())
+ .address(registrationDto.getAddress())
+ .dateOfBirth(registrationDto.getDateOfBirth())
+ .email(registrationDto.getEmail())
+ .phoneNumber(registrationDto.getPhoneNumber())
+ .password(registrationDto.getPassword())
+ .role(Role.ADMIN.name())
+ .build();
}
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/repository/OtpRepo.java b/InternSathi/src/main/java/internsathi/javaAssignment/repository/OtpRepo.java
new file mode 100644
index 0000000..2a6f4a6
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/repository/OtpRepo.java
@@ -0,0 +1,13 @@
+package internsathi.javaAssignment.repository;
+
+import internsathi.javaAssignment.entity.Otp;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Optional;
+
+public interface OtpRepo extends JpaRepository {
+
+ @Query("select o from Otp o where o.username = ?2 and o.otpKey = ?1")
+ Optional findOtpByUsernameAndOtpKey(String otpKey, String username);
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/repository/UserRepository.java b/InternSathi/src/main/java/internsathi/javaAssignment/repository/UserRepository.java
index 4197f78..7db5daf 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/repository/UserRepository.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/repository/UserRepository.java
@@ -1,13 +1,24 @@
package internsathi.javaAssignment.repository;
import internsathi.javaAssignment.entity.User;
+import jakarta.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
+import javax.swing.text.html.Option;
import java.util.Optional;
+@Transactional
public interface UserRepository extends JpaRepository {
@Query("select u from User u where u.username = ?1")
Optional findByUsername(String username);
+
+ @Query("select u from User u where u.username = ?1 and u.email = ?2")
+ Optional findByUsernameAndEmail(String username, String email);
+
+ @Modifying
+ @Query("update User u set u.password=?2 where u.username =?1")
+ void updateUserPassword(String username, String password);
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/security/SecurityConfig.java b/InternSathi/src/main/java/internsathi/javaAssignment/security/SecurityConfig.java
index 85043cc..8a79033 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/security/SecurityConfig.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/security/SecurityConfig.java
@@ -1,13 +1,13 @@
package internsathi.javaAssignment.security;
-import internsathi.javaAssignment.security.filter.CustomAuthenticationFilter;
import internsathi.javaAssignment.security.filter.JwtAuthenticationTokenFilter;
import internsathi.javaAssignment.security.manager.CustomAuthenticationManager;
+import internsathi.javaAssignment.security.provider.CustomAuthenticationProvider;
import internsathi.javaAssignment.security.token.JwtTokenService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@@ -30,12 +30,16 @@ public SecurityFilterChain appConfig(HttpSecurity http) throws Exception {
return http
.csrf()
.disable()
- //.addFilterAt(new CustomAuthenticationFilter(authenticationManger, jwtTokenService), UsernamePasswordAuthenticationFilter.class)
- .addFilterBefore(new JwtAuthenticationTokenFilter(userDetailsService, new JwtTokenService(userDetailsService)), UsernamePasswordAuthenticationFilter.class)
+ .addFilterAt(new JwtAuthenticationTokenFilter(userDetailsService, new JwtTokenService(userDetailsService)), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/css/**").permitAll()
- .requestMatchers("/internsathi/user/login").permitAll()
+ .requestMatchers(
+ "/internsathi/user/login",
+ "/internsathi/user/registerUser",
+ "/internsathi/user/resetPassword",
+ "/internsathi/user/otpVerification",
+ "/internsathi/rc/login").permitAll()
.requestMatchers("/internsathi/user/registerUser").permitAll()
.anyRequest().authenticated()
)
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/CustomAuthenticationFilter.java b/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/CustomAuthenticationFilter.java
deleted file mode 100644
index eb4bdba..0000000
--- a/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/CustomAuthenticationFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package internsathi.javaAssignment.security.filter;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import internsathi.javaAssignment.dto.LoginDto;
-import internsathi.javaAssignment.security.manager.CustomAuthenticationManager;
-import internsathi.javaAssignment.security.token.JwtTokenService;
-import internsathi.javaAssignment.security.token.TokenProperties;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
-import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-@Configuration
-public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
-
- private final CustomAuthenticationManager authenticationManager;
- private final JwtTokenService jwtTokenService;
-
- public CustomAuthenticationFilter(CustomAuthenticationManager authenticationManager, JwtTokenService jwtTokenService) {
- super(authenticationManager);
- this.authenticationManager = authenticationManager;
- this.jwtTokenService = jwtTokenService;
- }
-
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
- LoginDto loginUser;
- try {
- loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginDto.class);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
- loginUser.getUsername(),
- loginUser.getPassword(),
- new ArrayList<>()
- );
-
- return authenticationManager.authenticate(authenticationToken);
- }
-
- @Override
- protected void successfulAuthentication(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain chain,
- Authentication authResult) throws IOException, ServletException {
- String principal = (String) authResult.getPrincipal();
- Collection extends GrantedAuthority> authorities = authResult.getAuthorities();
- String token = null;
- Map accessToken = new HashMap<>();
-
- // Create Jwt token
- try {
- token = jwtTokenService.generateToken(principal);
- accessToken.put("access_token", token);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- // Add Bearer token in authorization header
- response.addHeader(TokenProperties.HEADER_STRING, TokenProperties.TOKEN_PREFIX + token);
-
-
- // Send access token as response
- response.setContentType("application/json");
- response.setCharacterEncoding("UTF-8");
- response.getWriter().write("{ \n \"access_token\" : "
- + "\"" + accessToken.get("access_token") + "\""
- + "\n}"
- );
- response.sendRedirect("/internsathi/user/home");
- }
-}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/JwtAuthenticationTokenFilter.java b/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/JwtAuthenticationTokenFilter.java
index fb8a92a..cfe9c51 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/JwtAuthenticationTokenFilter.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/security/filter/JwtAuthenticationTokenFilter.java
@@ -1,5 +1,6 @@
package internsathi.javaAssignment.security.filter;
+import internsathi.javaAssignment.security.provider.CustomAuthenticationProvider;
import internsathi.javaAssignment.security.token.JwtTokenService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -12,6 +13,7 @@
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.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -35,14 +37,17 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenService.validateToken(token, userDetails)) {
+ System.out.println(userDetails.getPassword());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
-
authenticationToken.setDetails(new WebAuthenticationDetails(request));
- SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+
+ if (authenticationToken.isAuthenticated()) {
+ SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+ }
}
}
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/security/token/JwtTokenService.java b/InternSathi/src/main/java/internsathi/javaAssignment/security/token/JwtTokenService.java
index 8a6e965..ab4af2f 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/security/token/JwtTokenService.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/security/token/JwtTokenService.java
@@ -39,11 +39,12 @@ public String generateToken(String username) {
userDetails.getAuthorities().forEach(
grantedAuthority -> roles.add(Role.valueOf(grantedAuthority.getAuthority()))
);
- Map authority = new HashMap<>();
- authority.put("Role", roles);
+ Map claims = new HashMap<>();
+ claims.put("Role", roles);
+ claims.put("sub", username);
+
return Jwts.builder()
- .setSubject(username)
- .setClaims(authority)
+ .setClaims(claims)
.setIssuedAt(new Date())
.setExpiration(generateExpirationDate())
.signWith(getSignInKey(), SIGNATURE_ALGORITHM)
@@ -71,7 +72,7 @@ public String getUsernameFromToken(String token) {
try {
final Claims claims = this.getAllClaimsFromToken(token);
assert claims != null;
- username = claims.getSubject();
+ username = (String) claims.get("sub");
} catch (Exception exception) {
return null;
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/service/EmailService.java b/InternSathi/src/main/java/internsathi/javaAssignment/service/EmailService.java
new file mode 100644
index 0000000..6e4bdf2
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/service/EmailService.java
@@ -0,0 +1,9 @@
+package internsathi.javaAssignment.service;
+
+import internsathi.javaAssignment.entity.EmailMessage;
+
+public interface EmailService {
+ void sendEmail(EmailMessage emailMessage, String username);
+
+ boolean verifyOtp(String otpKey, String username);
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/service/UserService.java b/InternSathi/src/main/java/internsathi/javaAssignment/service/UserService.java
index cfa6752..476b1bc 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/service/UserService.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/service/UserService.java
@@ -2,8 +2,20 @@
import internsathi.javaAssignment.dto.UserRegistrationDto;
import internsathi.javaAssignment.dto.UserRegistrationResponseDto;
+import internsathi.javaAssignment.entity.User;
+
+import java.util.List;
public interface UserService {
UserRegistrationResponseDto registerUser(UserRegistrationDto userRegistrationDetails) throws Exception;
+
+ boolean doesEmailAndUsernameExits(String username, String email);
+
+ void updatePassword(String username, String password);
+
+ List getAllUser();
+
+ void deleteUserById(Long userId);
+
}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/EmailServiceImplementation.java b/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/EmailServiceImplementation.java
new file mode 100644
index 0000000..3ae6d0b
--- /dev/null
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/EmailServiceImplementation.java
@@ -0,0 +1,57 @@
+package internsathi.javaAssignment.serviceImplementation;
+
+import internsathi.javaAssignment.entity.EmailMessage;
+import internsathi.javaAssignment.entity.Otp;
+import internsathi.javaAssignment.repository.OtpRepo;
+import internsathi.javaAssignment.service.EmailService;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+import java.util.Random;
+
+@Service
+public class EmailServiceImplementation implements EmailService {
+
+ private final JavaMailSender javaMailSender;
+ private final OtpRepo otpRepo;
+
+ public EmailServiceImplementation(JavaMailSender javaMailSender, OtpRepo otpRepo) {
+ this.javaMailSender = javaMailSender;
+ this.otpRepo = otpRepo;
+ }
+
+ @Override
+ public void sendEmail(EmailMessage emailMessage, String username) {
+ SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
+ String otpKey = generateOtpKey();
+ Otp otp = new Otp(username, otpKey);
+ otpRepo.save(otp);
+
+ simpleMailMessage.setFrom("ajaymaharjan0007@gmail.com");
+ simpleMailMessage.setTo(emailMessage.getMailTo());
+ simpleMailMessage.setSubject(EmailMessage.EMAIL_SUBJECT);
+ simpleMailMessage.setText(emailMessage.getMessage() + otpKey);
+
+ this.javaMailSender.send(simpleMailMessage);
+ }
+
+ @Override
+ public boolean verifyOtp(String otpKey, String username) {
+ Optional otp = otpRepo.findOtpByUsernameAndOtpKey(otpKey, username);
+ return otp.isPresent();
+ }
+
+ private String generateOtpKey() {
+ String digits = "0123456789";
+ int lengthOfOtp = 6;
+ Random random = new Random();
+ StringBuilder otp = new StringBuilder();
+ for (int i = 0; i < lengthOfOtp; i++) {
+ int index = random.nextInt(digits.length());
+ otp.append(digits.charAt(index));
+ }
+ return otp.toString();
+ }
+}
diff --git a/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/UserServiceImplementation.java b/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/UserServiceImplementation.java
index fe55ac3..d8ed5b7 100644
--- a/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/UserServiceImplementation.java
+++ b/InternSathi/src/main/java/internsathi/javaAssignment/serviceImplementation/UserServiceImplementation.java
@@ -2,32 +2,34 @@
import internsathi.javaAssignment.dto.UserRegistrationDto;
import internsathi.javaAssignment.dto.UserRegistrationResponseDto;
+import internsathi.javaAssignment.entity.EmailMessage;
import internsathi.javaAssignment.entity.User;
import internsathi.javaAssignment.mapper.UserMapper;
import internsathi.javaAssignment.model.UserSecurity;
import internsathi.javaAssignment.repository.UserRepository;
+import internsathi.javaAssignment.service.EmailService;
import internsathi.javaAssignment.service.UserService;
import org.springframework.http.HttpStatus;
-import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
-import javax.swing.text.html.Option;
+import java.util.List;
import java.util.Optional;
-import java.util.function.Function;
@Service
public class UserServiceImplementation implements UserDetailsService, UserService {
private final UserRepository userRepo;
private final PasswordEncoder passwordEncoder;
+ private final EmailService emailService;
- public UserServiceImplementation(UserRepository userRepo, PasswordEncoder passwordEncoder) {
+ public UserServiceImplementation(UserRepository userRepo, PasswordEncoder passwordEncoder, EmailService emailService) {
this.userRepo = userRepo;
this.passwordEncoder = passwordEncoder;
+ this.emailService = emailService;
}
@Override
@@ -51,4 +53,33 @@ public UserRegistrationResponseDto registerUser(UserRegistrationDto userRegistra
.build()
).orElseThrow(() -> new RuntimeException("User Registration Failed"));
}
+
+ @Override
+ public boolean doesEmailAndUsernameExits(String username, String email) {
+ boolean userAvailable = userRepo.findByUsernameAndEmail(username, email)
+ .isPresent();
+ if (userAvailable) {
+ emailService.sendEmail(
+ new EmailMessage(email), username
+ );
+ }
+ return userAvailable;
+ }
+
+ @Override
+ public void updatePassword(String username, String password) {
+ password = passwordEncoder.encode(password);
+ userRepo.updateUserPassword(username, password);
+
+ }
+
+ @Override
+ public List getAllUser() {
+ return userRepo.findAll();
+ }
+
+ @Override
+ public void deleteUserById(Long userId) {
+ userRepo.deleteById(userId);
+ }
}
diff --git a/InternSathi/src/main/resources/application.yml b/InternSathi/src/main/resources/application.yml
index 9e8254c..382249f 100644
--- a/InternSathi/src/main/resources/application.yml
+++ b/InternSathi/src/main/resources/application.yml
@@ -15,3 +15,19 @@ spring:
username: postgres
password: 8956
+ mail:
+ host: smtp.gmail.com
+ port: 587
+ username: your_email
+ password: your_email_password
+ properties:
+ mail:
+ smtp:
+ auth: true
+ starttls:
+ enable: true
+ sql:
+ init:
+ data-locations: classpath:/db/data.sql
+ mode: embedded
+
diff --git a/InternSathi/src/main/resources/db/data.sql b/InternSathi/src/main/resources/db/data.sql
new file mode 100644
index 0000000..fcf5731
--- /dev/null
+++ b/InternSathi/src/main/resources/db/data.sql
@@ -0,0 +1,14 @@
+Insert Into tb_users
+ (id, address, date_of_birth, email, name, password, phone_number, role, username) values
+ (10000, 'asdf-123', '1999-09-09', 'ajaymaharjan0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 9882918100, 'USER, ADMIN', 'am0007'),
+ (10001, 'asdf-123', '1999-09-02', 'asdf@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 988291800, 'USER', 'adf007'),
+ (10002, 'asdf-123', '1999-09-03', 'asdf@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 98829100, 'USER', 'am000asdf7'),
+ (10003, 'asdf-123', '1999-09-04', 'gfh@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 9888100, 'USER', 'am00fds07'),
+ (10004, 'asdf-123', '1999-09-05', 'ajasadfymaharjan0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 291800, 'USER', 'aasm0007'),
+ (10005, 'asdf-123', '1999-09-06', 'ajaymahhfdsarjan0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 9291100, 'USER', 'asd007'),
+ (10006, 'asdf-123', '1999-09-07', 'ajaymaharjaweqn0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 988100, 'USER', 'am00saa07'),
+ (10007, 'asdf-123', '1999-09-07', 'ajaymaharjan00svc07@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 9882100, 'USER', 'am00asdf07'),
+ (10008, 'asdf-123', '1999-09-08', 'ajaymaharjan00012347@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 2918100, 'USER', 'am0sd007'),
+ (10009, 'asdf-123', '1999-09-09', 'ajaymaharja21n0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 82918100, 'USER', 'am00qwe07'),
+ (10010, 'asdf-123', '1999-09-09', 'ajaymaharjasan0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 92918100, 'USER', 'am00zxc07'),
+ (10011, 'asdf-123', '1999-09-01', 'maharjanajay0007@gmail.com', 'Ajay Maharjan', '$2a$12$ExXKqOUveuCt1OUDKxN8euN6sFnUjg6qXwUo0bpdWrI6KrhtDxSgq', 988218100, 'USER', 'am007');
diff --git a/InternSathi/src/main/resources/static/css/style2.css b/InternSathi/src/main/resources/static/css/style2.css
index b5e2f6b..c6ea434 100644
--- a/InternSathi/src/main/resources/static/css/style2.css
+++ b/InternSathi/src/main/resources/static/css/style2.css
@@ -176,4 +176,47 @@ footer {
.logout-button .navbar-nav .nav-item a {
text-decoration: none;
color: white;
-}
\ No newline at end of file
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 20px;
+}
+
+th, td {
+ padding: 12px;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+}
+
+th {
+ background-color: #f2f2f2;
+}
+
+a.delete-user-link {
+ color: #dc3545;
+ text-decoration: none;
+ margin-right: 10px;
+}
+
+a.delete-user-link:hover {
+ text-decoration: underline;
+}
+
+button.update-button,
+button.delete-button {
+ margin-right: 10px;
+ padding: 8px 15px;
+ background-color: #007bff;
+ border: none;
+ color: #fff;
+ border-radius: 5px;
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+}
+
+button.update-button:hover,
+button.delete-button:hover {
+ background-color: #0056b3;
+}
diff --git a/InternSathi/src/main/resources/templates/forgetPassword.html b/InternSathi/src/main/resources/templates/forgetPassword.html
new file mode 100644
index 0000000..260fb8f
--- /dev/null
+++ b/InternSathi/src/main/resources/templates/forgetPassword.html
@@ -0,0 +1,48 @@
+
+
+
+
+ Reset Password
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InternSathi/src/main/resources/templates/home.html b/InternSathi/src/main/resources/templates/home.html
deleted file mode 100644
index 145c6b5..0000000
--- a/InternSathi/src/main/resources/templates/home.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
- InternSathi - Home
-
-
-
-
-
-
- Authentication Successful,
-
-
-
-
-
-
-
-
diff --git a/InternSathi/src/main/resources/templates/login.html b/InternSathi/src/main/resources/templates/login.html
index 81775f4..61a8f4f 100644
--- a/InternSathi/src/main/resources/templates/login.html
+++ b/InternSathi/src/main/resources/templates/login.html
@@ -12,9 +12,11 @@ InternSathi