Add username validation and password breach check to signup
- Enforced alphanumeric-only usernames using regex validation. - Passwords must be >= 8 chars and checked against haveibeenpwned.com. - Improved SignupRequest DTO with validation annotations. - Implemented UserService to handle password validation and encoding.
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.controller;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.SignupRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.service.UserService;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/auth")
|
||||||
|
public class SignupController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public SignupController(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/signup")
|
||||||
|
public ResponseEntity<?> signup(@Valid @RequestBody SignupRequest request) {
|
||||||
|
userService.registerUser(request);
|
||||||
|
return ResponseEntity.ok("User registered successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class SignupRequest {
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "Username must be alphanumeric only")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Email
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 8, message = "Password must be at least 8 characters long")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.SignupRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerUser(SignupRequest request) {
|
||||||
|
if (isPasswordPwned(request.getPassword())) {
|
||||||
|
throw new IllegalArgumentException("Password has been compromised in data breaches.");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(request.getUsername());
|
||||||
|
user.setEmail(request.getEmail());
|
||||||
|
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPasswordPwned(String password) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||||
|
byte[] hash = md.digest(password.getBytes());
|
||||||
|
String fullHash = String.format("%040x", new BigInteger(1, hash)).toUpperCase();
|
||||||
|
String prefix = fullHash.substring(0, 5);
|
||||||
|
String suffix = fullHash.substring(5);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
String response = restTemplate.getForObject("https://api.pwnedpasswords.com/range/" + prefix, String.class);
|
||||||
|
|
||||||
|
return response != null && response.contains(suffix);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false; // If API fails, allow but log in production
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user