Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.podzilla.auth.model.User;
import com.podzilla.auth.service.AdminService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -19,6 +21,10 @@ public AdminController(final AdminService adminService) {
}

@GetMapping("/users")
@Operation(summary = "Get all users",
description = "Fetches all users in the system.")
@ApiResponse(responseCode = "200",
description = "Users fetched successfully")
public List<User> getUsers() {
return adminService.getUsers();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import com.podzilla.auth.dto.LoginRequest;
import com.podzilla.auth.dto.SignupRequest;
import com.podzilla.auth.service.AuthenticationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -22,9 +23,6 @@ public class AuthenticationController {

private final AuthenticationService authenticationService;

private final SecurityContextLogoutHandler logoutHandler =
new SecurityContextLogoutHandler();

private static final Logger LOGGER =
LoggerFactory.getLogger(AuthenticationController.class);

Expand All @@ -35,59 +33,72 @@ public AuthenticationController(
}

@PostMapping("/login")
@Operation(
summary = "Login",
description = "Logs in a user and generates JWT tokens."
)
@ApiResponse(
responseCode = "200",
description = "User logged in successfully"
)
public ResponseEntity<?> login(
@RequestBody final LoginRequest loginRequest,
final HttpServletResponse response) {
try {
String email = authenticationService.login(loginRequest, response);
LOGGER.info("User {} logged in", email);
return new ResponseEntity<>(
"User " + email + " logged in successfully",
HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(e.getMessage());
return new ResponseEntity<>(e.getMessage(),
HttpStatus.UNAUTHORIZED);
}
String email = authenticationService.login(loginRequest, response);
LOGGER.info("User {} logged in", email);
return new ResponseEntity<>(
"User " + email + " logged in successfully",
HttpStatus.OK);
}

@PostMapping("/register")
@Operation(
summary = "Register",
description = "Registers a new user."
)
@ApiResponse(
responseCode = "201",
description = "User registered successfully"
)
public ResponseEntity<?> registerUser(
@RequestBody final SignupRequest signupRequest,
final HttpServletRequest request) {
try {
authenticationService.registerAccount(signupRequest);
LOGGER.info("User {} registered", signupRequest.getEmail());
return new ResponseEntity<>("Account registered.",
HttpStatus.CREATED);
} catch (Exception e) {
LOGGER.error(e.getMessage());
return new ResponseEntity<>(e.getMessage(),
HttpStatus.UNAUTHORIZED);
}
@RequestBody final SignupRequest signupRequest) {
authenticationService.registerAccount(signupRequest);
LOGGER.info("User {} registered", signupRequest.getEmail());
return new ResponseEntity<>("Account registered.",
HttpStatus.CREATED);
}

@PostMapping("/logout")
@Operation(
summary = "Logout",
description = "Logs out a user and invalidates JWT tokens."
)
@ApiResponse(
responseCode = "200",
description = "User logged out successfully"
)
public ResponseEntity<?> logoutUser(final HttpServletResponse response) {
authenticationService.logoutUser(response);
return new ResponseEntity<>("You've been signed out!", HttpStatus.OK);
}

@PostMapping("/refresh-token")
@Operation(
summary = "Refresh Token",
description = "Refreshes the JWT tokens for a logged-in user."
)
@ApiResponse(
responseCode = "200",
description = "Token refreshed successfully"
)
public ResponseEntity<?> refreshToken(
final HttpServletRequest request,
final HttpServletResponse response) {
try {
String email = authenticationService.refreshToken(
request, response);
LOGGER.info("User {} refreshed token", email);
return new ResponseEntity<>(
"User " + email + " refreshed token successfully",
HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(e.getMessage());
return new ResponseEntity<>(e.getMessage(),
HttpStatus.UNAUTHORIZED);
}
String email = authenticationService.refreshToken(
request, response);
LOGGER.info("User {} refreshed token", email);
return new ResponseEntity<>(
"User " + email + " refreshed tokens successfully",
HttpStatus.OK);
}
}
23 changes: 0 additions & 23 deletions src/main/java/com/podzilla/auth/controller/ResourceController.java

This file was deleted.

19 changes: 19 additions & 0 deletions src/main/java/com/podzilla/auth/exception/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.podzilla.auth.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

import java.time.LocalDateTime;

@Getter
public class ErrorResponse {
private final String message;
private final HttpStatus status;
private final LocalDateTime timestamp;

public ErrorResponse(final String message, final HttpStatus status) {
this.message = message;
this.status = status;
this.timestamp = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.podzilla.auth.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFoundException(
final NotFoundException exception) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(exception.getMessage(),
HttpStatus.NOT_FOUND));
}

@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
final ValidationException exception) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(exception.getMessage(),
HttpStatus.BAD_REQUEST));
}

@ExceptionHandler(InvalidActionException.class)
public ResponseEntity<ErrorResponse> handleInvalidActionException(
final InvalidActionException exception) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(exception.getMessage(),
HttpStatus.BAD_REQUEST));
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(
final Exception exception) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(exception.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.podzilla.auth.exception;

public class InvalidActionException extends RuntimeException {
public InvalidActionException(final String message) {
super("Invalid action: " + message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.podzilla.auth.exception;

public class NotFoundException extends RuntimeException {
public NotFoundException(final String message) {
super("Not Found: " + message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.podzilla.auth.exception;

public class ValidationException extends RuntimeException {
public ValidationException(final String message) {
super("Validation error: " + message);
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/podzilla/auth/security/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ SecurityFilterChain securityFilterChain(final HttpSecurity http)
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**")
.hasRole("ADMIN")
.requestMatchers("/swagger-ui/**",
"/v3/api-docs/**").permitAll()
.anyRequest().authenticated()

)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.podzilla.auth.dto.LoginRequest;
import com.podzilla.auth.dto.SignupRequest;
import com.podzilla.auth.exception.ValidationException;
import com.podzilla.auth.model.ERole;
import com.podzilla.auth.model.Role;
import com.podzilla.auth.model.User;
import com.podzilla.auth.repository.RoleRepository;
import com.podzilla.auth.repository.UserRepository;
import jakarta.persistence.EntityExistsException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
Expand Down Expand Up @@ -66,7 +66,7 @@ public String login(final LoginRequest loginRequest,

public void registerAccount(final SignupRequest signupRequest) {
if (userRepository.existsByEmail(signupRequest.getEmail())) {
throw new EntityExistsException("Email already used");
throw new ValidationException("Email already in use.");
}

User account = new User(
Expand All @@ -92,7 +92,7 @@ public String refreshToken(final HttpServletRequest request,
tokenService.generateAccessToken(email, response);
return email;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid refresh token");
throw new ValidationException("Invalid refresh token.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.podzilla.auth.service;

import com.podzilla.auth.exception.NotFoundException;
import com.podzilla.auth.model.User;
import com.podzilla.auth.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 java.util.Set;
Expand All @@ -24,11 +24,10 @@ public CustomUserDetailsService(final UserRepository userRepository) {
}

@Override
public UserDetails loadUserByUsername(final String email)
throws UsernameNotFoundException {
public UserDetails loadUserByUsername(final String email) {
User user = userRepository.findByEmail(email)
.orElseThrow(() ->
new UsernameNotFoundException(
new NotFoundException(
email + " not found."));

Set<GrantedAuthority> authorities = user
Expand Down
Loading