Skip to content
Merged
16 changes: 16 additions & 0 deletions src/main/java/org/example/alfs/config/PasswordConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.example.alfs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class PasswordConfig {

// Makes password encoder available in the whole app
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
39 changes: 39 additions & 0 deletions src/main/java/org/example/alfs/controllers/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.example.alfs.controllers;

import org.example.alfs.dto.auth.LoginRequestDTO;
import org.example.alfs.dto.auth.LoginResponseDTO;
import org.example.alfs.entities.User;
import org.example.alfs.services.AuthService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.Valid;

@RestController
@RequestMapping("/auth")
public class AuthController {

private final AuthService authService;

public AuthController(AuthService authService) {
this.authService = authService;
}

/**
* Handles user login by validating credentials and returning user details.
*/
@PostMapping("/login")
public LoginResponseDTO login(@Valid @RequestBody LoginRequestDTO request) {

User user = authService.login(
request.getUsername(),
request.getPassword()
);

return new LoginResponseDTO(
user.getUsername(),
user.getRole().name()
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
17 changes: 17 additions & 0 deletions src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.example.alfs.dto.auth;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class LoginRequestDTO {

@NotBlank(message = "Username is required")
private String username;

@NotBlank(message = "Password is required")
private String password;
Comment thread
simonforsberg marked this conversation as resolved.

}
12 changes: 12 additions & 0 deletions src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.alfs.dto.auth;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class LoginResponseDTO {

private String username;
private String role;
}
8 changes: 8 additions & 0 deletions src/main/java/org/example/alfs/entities/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ public class User {
private String passwordHash;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
Comment on lines +30 to 31

@coderabbitai coderabbitai Bot Apr 2, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure existing users have roles before applying this constraint.

Adding nullable = false to an existing column requires that no null values exist in the database. If there are existing users with null roles, the schema migration will fail or existing users will cause NullPointerException in AuthController.login() when calling user.getRole().name().

Consider adding a data migration (e.g., Flyway/Liquibase script or a SQL update) to set a default role for any existing null values before this constraint is enforced:

UPDATE users SET role = 'REPORTER' WHERE role IS NULL;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/entities/User.java` around lines 30 - 31, The
User.role field was changed to `@Column`(nullable = false) which will break
migrations if existing user rows have NULL and can cause NPE in
AuthController.login() where user.getRole().name() is called; before enforcing
this constraint, add a data migration (Flyway/Liquibase or raw SQL) that sets a
sensible default for existing null roles (e.g., update users set role='REPORTER'
where role is null) and then apply the schema change, ensuring
AuthController.login() and the User entity are safe from null roles.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont have any existing database or persisted users yet, so this wont cause issues in our current setup. We'll handle migrations properly when we introduce a real database.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addee1, that makes sense — since there's no existing database or persisted users yet, the nullable = false constraint won't cause any migration issues right now, and the @PrePersist callback already guards against null roles on new entities.

Just a reminder for when you introduce a real database: before applying this schema constraint in a migration script, make sure to run a backfill like the one suggested (e.g., UPDATE users SET role = 'REPORTER' WHERE role IS NULL;) before or alongside the ALTER TABLE step to avoid migration failures on any pre-existing data.


@PrePersist
public void prePersist() {
if (role == null) {
role = Role.REPORTER;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@

public interface UserRepository extends JpaRepository<User, Long> {

Optional<User> findByUsername(String username);
}
40 changes: 40 additions & 0 deletions src/main/java/org/example/alfs/services/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.example.alfs.services;

import org.example.alfs.entities.User;
import org.example.alfs.repositories.UserRepository;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

@Service
public class AuthService {

private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;

public AuthService(PasswordEncoder passwordEncoder, UserRepository userRepository) {
this.passwordEncoder = passwordEncoder;
this.userRepository = userRepository;
}

/**
* Authenticates a user by verifying username and password.
*/
public User login(String username, String password) {

User user = userRepository.findByUsername(username)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.UNAUTHORIZED,
"Invalid username or password"
));
if (!passwordEncoder.matches(password, user.getPasswordHash())) {
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED,
"Invalid username or password"
);
}

return user;
}
}
Loading