diff --git a/src/main/java/com/safetypin/authentication/controller/AuthenticationController.java b/src/main/java/com/safetypin/authentication/controller/AuthenticationController.java index 5d5566f5b23331456ee7288d4a16e206b49197d1..1b5f7aafe21ffb59872d76dd4c53487425ae9a37 100644 --- a/src/main/java/com/safetypin/authentication/controller/AuthenticationController.java +++ b/src/main/java/com/safetypin/authentication/controller/AuthenticationController.java @@ -4,16 +4,13 @@ import com.safetypin.authentication.dto.*; import com.safetypin.authentication.exception.InvalidCredentialsException; import com.safetypin.authentication.exception.UserAlreadyExistsException; import com.safetypin.authentication.service.AuthenticationService; -import jakarta.validation.Valid; import com.safetypin.authentication.service.GoogleAuthService; import com.safetypin.authentication.service.JwtService; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import com.safetypin.authentication.dto.VerifyResetOTPRequest; -import com.safetypin.authentication.dto.PasswordResetWithOTPRequest; -import com.safetypin.authentication.dto.ResetTokenResponse; @RestController @RequestMapping("/api/auth") @@ -90,14 +87,14 @@ public class AuthenticationController { public ResponseEntity<AuthResponse> forgotPassword(@Valid @RequestBody PasswordResetRequest request) { try { authenticationService.forgotPassword(request.getEmail()); - return ResponseEntity.ok(new AuthResponse(true, - "Password reset OTP has been sent to your email", null)); + return ResponseEntity.ok(new AuthResponse(true, + "Password reset OTP has been sent to your email", null)); } catch (IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(new AuthResponse(false, e.getMessage(), null)); + .body(new AuthResponse(false, e.getMessage(), null)); } } - + // Endpoint to verify OTP for password reset @PostMapping("/verify-reset-otp") public ResponseEntity<AuthResponse> verifyResetOTP(@Valid @RequestBody VerifyResetOTPRequest request) { @@ -105,28 +102,28 @@ public class AuthenticationController { String resetToken = authenticationService.verifyPasswordResetOTP(request.getEmail(), request.getOtp()); if (resetToken != null) { ResetTokenResponse tokenResponse = new ResetTokenResponse(resetToken); - return ResponseEntity.ok(new AuthResponse(true, - "OTP verified successfully. Reset token valid for 3 minutes.", tokenResponse)); + return ResponseEntity.ok(new AuthResponse(true, + "OTP verified successfully. Reset token valid for 3 minutes.", tokenResponse)); } else { return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(new AuthResponse(false, "Invalid OTP", null)); + .body(new AuthResponse(false, "Invalid OTP", null)); } } catch (IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(new AuthResponse(false, e.getMessage(), null)); + .body(new AuthResponse(false, e.getMessage(), null)); } } - + // Endpoint to reset password with reset token @PostMapping("/reset-password") public ResponseEntity<AuthResponse> resetPassword(@Valid @RequestBody PasswordResetWithOTPRequest request) { try { authenticationService.resetPassword(request.getEmail(), request.getNewPassword(), request.getResetToken()); - return ResponseEntity.ok(new AuthResponse(true, - "Password has been reset successfully", null)); + return ResponseEntity.ok(new AuthResponse(true, + "Password has been reset successfully", null)); } catch (InvalidCredentialsException | IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(new AuthResponse(false, e.getMessage(), null)); + .body(new AuthResponse(false, e.getMessage(), null)); } } diff --git a/src/main/java/com/safetypin/authentication/service/GoogleAuthService.java b/src/main/java/com/safetypin/authentication/service/GoogleAuthService.java index ce8ef7ad860c7fe5af0ffade7017a4dcfd264664..9aa24c0a65449f8f086de17392622c41be999bd6 100644 --- a/src/main/java/com/safetypin/authentication/service/GoogleAuthService.java +++ b/src/main/java/com/safetypin/authentication/service/GoogleAuthService.java @@ -10,7 +10,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; - import com.safetypin.authentication.dto.GoogleAuthDTO; import com.safetypin.authentication.exception.ApiException; import com.safetypin.authentication.exception.InvalidCredentialsException; @@ -22,8 +21,14 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.io.*; -import java.net.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; import java.security.GeneralSecurityException; import java.time.LocalDate; import java.time.Year; @@ -33,21 +38,16 @@ import java.util.Optional; @Service public class GoogleAuthService { private static final Logger logger = LoggerFactory.getLogger(GoogleAuthService.class); - + private static final String EMAIL_PROVIDER = "GOOGLE"; + private static final String PEOPLE_API_BASE_URL = "https://people.googleapis.com/v1/people/me"; + private static final String BIRTHDAY = "birthdays"; private final UserService userService; private final JwtService jwtService; - @Value("${google.client.id:default}") private String googleClientId; - @Value("${google.client.secret:default}") private String googleClientSecret; - private static final String EMAIL_PROVIDER = "GOOGLE"; - private static final String PEOPLE_API_BASE_URL = "https://people.googleapis.com/v1/people/me"; - - private static final String BIRTHDAY = "birthdays"; - public GoogleAuthService(UserService userService, JwtService jwtService) { this.userService = userService; this.jwtService = jwtService; diff --git a/src/main/java/com/safetypin/authentication/service/JwtService.java b/src/main/java/com/safetypin/authentication/service/JwtService.java index e312b56b08533522f8c47808cc1f1556ef765fa0..ebe93a7931ec9a42edb589b0707c58a7bb55e4db 100644 --- a/src/main/java/com/safetypin/authentication/service/JwtService.java +++ b/src/main/java/com/safetypin/authentication/service/JwtService.java @@ -7,8 +7,8 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; -import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; import java.security.Key; import java.util.Date; diff --git a/src/main/resources/application-staging.properties b/src/main/resources/application-staging.properties index 8491638fcdc38630d4c9b9b2ffafac01f9774c36..28ffb701fb5cd74eeada43f668f3f8ed1a81d590 100644 --- a/src/main/resources/application-staging.properties +++ b/src/main/resources/application-staging.properties @@ -1,12 +1,9 @@ spring.application.name=authentication - spring.datasource.url=${JDBC_STAGING_DATABASE_URL} spring.datasource.username=${JDBC_STAGING_DATABASE_USERNAME} spring.datasource.password=${JDBC_STAGING_DATABASE_PASSWORD} - spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect - # Hibernate Properties spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1f57723b9a70ad73a3d55c4e9401aa7f9b34885a..f2b5d3953329b54e184cbe57d229a6bf27c0b638 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,5 @@ spring.application.name=authentication spring.profiles.active=${PRODUCTION:dev} - # Spring Mail spring.mail.host=smtp.gmail.com spring.mail.port=587 @@ -9,7 +8,6 @@ spring.mail.password=${MAIL_PASSWORD} spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true - google.client.id=${GOOGLE_CLIENT_ID:default} google.client.secret=${GOOGLE_CLIENT_SECRET:default} jwt.secret=${JWT_SECRET:biggerboysandstolensweetheartsss} \ No newline at end of file diff --git a/src/test/java/com/safetypin/authentication/dto/ErrorResponseTest.java b/src/test/java/com/safetypin/authentication/dto/ErrorResponseTest.java index a5249ce2e9c1050524682f320ecfb1b8f8338ec3..f15051f0835905fa41fe0c3b2056455be863abfa 100644 --- a/src/test/java/com/safetypin/authentication/dto/ErrorResponseTest.java +++ b/src/test/java/com/safetypin/authentication/dto/ErrorResponseTest.java @@ -1,7 +1,9 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; + import java.time.LocalDateTime; + import static org.junit.jupiter.api.Assertions.*; class ErrorResponseTest { @@ -26,7 +28,7 @@ class ErrorResponseTest { // Act ErrorResponse response = new ErrorResponse(status, message); LocalDateTime beforeTest = LocalDateTime.now().minusSeconds(1); - + // Assert assertEquals(status, response.getStatus()); assertEquals(message, response.getMessage()); @@ -73,10 +75,10 @@ class ErrorResponseTest { void testToString() { // Arrange ErrorResponse response = new ErrorResponse(404, "Not Found"); - + // Act String toStringResult = response.toString(); - + // Assert assertTrue(toStringResult.contains("404")); assertTrue(toStringResult.contains("Not Found")); diff --git a/src/test/java/com/safetypin/authentication/dto/PasswordResetRequestTest.java b/src/test/java/com/safetypin/authentication/dto/PasswordResetRequestTest.java index 9447b1c8b6201650a95f657c22cb0cb7d2bf9539..4b8c01136f2f0dfbc525e572fd8fb524b69b8622 100644 --- a/src/test/java/com/safetypin/authentication/dto/PasswordResetRequestTest.java +++ b/src/test/java/com/safetypin/authentication/dto/PasswordResetRequestTest.java @@ -1,7 +1,8 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; class PasswordResetRequestTest { diff --git a/src/test/java/com/safetypin/authentication/dto/PasswordResetWithOTPRequestTest.java b/src/test/java/com/safetypin/authentication/dto/PasswordResetWithOTPRequestTest.java index 41317eaf0d04826519b4bdef34b1d545a895f2ec..3e44e1efce0a26670410b040fb2ec0c89a696311 100644 --- a/src/test/java/com/safetypin/authentication/dto/PasswordResetWithOTPRequestTest.java +++ b/src/test/java/com/safetypin/authentication/dto/PasswordResetWithOTPRequestTest.java @@ -1,7 +1,8 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; class PasswordResetWithOTPRequestTest { diff --git a/src/test/java/com/safetypin/authentication/dto/RegistrationRequestTest.java b/src/test/java/com/safetypin/authentication/dto/RegistrationRequestTest.java index 02a7fc7c38617a7e814e645bea2921730484270a..5f1b1256ba802c20c0070511ab05f118025b93a5 100644 --- a/src/test/java/com/safetypin/authentication/dto/RegistrationRequestTest.java +++ b/src/test/java/com/safetypin/authentication/dto/RegistrationRequestTest.java @@ -1,8 +1,10 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; + import java.time.LocalDate; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; class RegistrationRequestTest { diff --git a/src/test/java/com/safetypin/authentication/dto/SocialLoginRequestTest.java b/src/test/java/com/safetypin/authentication/dto/SocialLoginRequestTest.java index ca7759815416a3b3edbe4f7e72f025adaa73a459..06d2cb60135e3337ca592b6eede5589c6246b711 100644 --- a/src/test/java/com/safetypin/authentication/dto/SocialLoginRequestTest.java +++ b/src/test/java/com/safetypin/authentication/dto/SocialLoginRequestTest.java @@ -1,8 +1,10 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; + import java.time.LocalDate; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; class SocialLoginRequestTest { diff --git a/src/test/java/com/safetypin/authentication/dto/VerifyResetOTPRequestTest.java b/src/test/java/com/safetypin/authentication/dto/VerifyResetOTPRequestTest.java index 74e170d03f1c64b8ba4ad6dbee1395c92ebfd96e..7b94fe18e14d8ae91b027a990bce5aeae9e0166b 100644 --- a/src/test/java/com/safetypin/authentication/dto/VerifyResetOTPRequestTest.java +++ b/src/test/java/com/safetypin/authentication/dto/VerifyResetOTPRequestTest.java @@ -1,7 +1,8 @@ package com.safetypin.authentication.dto; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; class VerifyResetOTPRequestTest { diff --git a/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java b/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java index a411399dd66ca0d35fcdc0818a7b16f5048dc95a..61eda1090ebca31354cf0a128fed6599e4dcb913 100644 --- a/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java +++ b/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java @@ -1,5 +1,9 @@ package com.safetypin.authentication.service; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; @@ -14,68 +18,54 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.Appender; import org.slf4j.LoggerFactory; import org.springframework.test.util.ReflectionTestUtils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.time.LocalDate; import java.util.Optional; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class GoogleAuthServiceTest { + private final String testAccessToken = "test-access-token"; + private final String testGoogleClientId = "test-client-id"; + private final String testIdToken = "test-id-token"; @Mock private UserService userService; - @Mock private JwtService jwtService; - @Mock private GoogleIdToken idToken; - @Mock private GoogleIdToken.Payload payload; - @Mock private GoogleIdTokenVerifier verifier; - @Mock private GoogleAuthorizationCodeTokenRequest tokenRequest; - @Mock private GoogleTokenResponse tokenResponse; - @Spy @InjectMocks private GoogleAuthService googleAuthService; - @Mock private Appender<ILoggingEvent> mockAppender; - @Captor private ArgumentCaptor<ILoggingEvent> loggingEventCaptor; - private GoogleAuthDTO googleAuthDTO; private UUID testUserId; - private final String testAccessToken = "test-access-token"; - - private final String testGoogleClientId = "test-client-id"; - - private final String testIdToken = "test-id-token"; - @BeforeEach void setup() { ReflectionTestUtils.setField(googleAuthService, "googleClientId", testGoogleClientId); diff --git a/src/test/java/com/safetypin/authentication/service/JwtServiceTest.java b/src/test/java/com/safetypin/authentication/service/JwtServiceTest.java index cc11b7f2cc730642b0dfff0a48ec9660e4aecdaa..d0d46a0b4cbc918d0173bfc519c3ff5e8ae22a73 100644 --- a/src/test/java/com/safetypin/authentication/service/JwtServiceTest.java +++ b/src/test/java/com/safetypin/authentication/service/JwtServiceTest.java @@ -21,15 +21,13 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class JwtServiceTest { - @Mock - private UserService userService; - - private JwtService jwtService; - private final String secretKey = "testSecretKeyWithAtLeast256BitsForHmacSha256Algorithm"; private final UUID userId = UUID.randomUUID(); private final User mockUser = mock(User.class); private final UserResponse mockUserResponse = mock(UserResponse.class); + @Mock + private UserService userService; + private JwtService jwtService; @BeforeEach void setUp() { diff --git a/src/test/java/com/safetypin/authentication/service/OTPServiceTest.java b/src/test/java/com/safetypin/authentication/service/OTPServiceTest.java index 24e6bbcbd8048749550d4cee17107372ef06aef8..0ea63d55bda276dea0910ca18105bed63f829e6b 100644 --- a/src/test/java/com/safetypin/authentication/service/OTPServiceTest.java +++ b/src/test/java/com/safetypin/authentication/service/OTPServiceTest.java @@ -269,10 +269,10 @@ class OTPServiceTest { Class<?> resetTokenDetailsClass = tokenDetails.getClass(); Constructor<?> constructor = resetTokenDetailsClass.getDeclaredConstructor(String.class, LocalDateTime.class); constructor.setAccessible(true); - + // Create a new ResetTokenDetails instance with an expired time (4 minutes ago) Object expiredTokenDetails = constructor.newInstance(email, LocalDateTime.now().minusMinutes(4)); - + // Replace the original token details with the expired one resetTokenStorage.put(resetToken, expiredTokenDetails); diff --git a/src/test/java/com/safetypin/authentication/service/TokenExpirationTest.java b/src/test/java/com/safetypin/authentication/service/TokenExpirationTest.java index 0b9ac09bf42c156f70fc5a11c813333207aa69c3..ebc4fa1e4c830005251954daea00db7088100bca 100644 --- a/src/test/java/com/safetypin/authentication/service/TokenExpirationTest.java +++ b/src/test/java/com/safetypin/authentication/service/TokenExpirationTest.java @@ -16,7 +16,8 @@ import java.util.Date; import java.util.Optional; import java.util.UUID; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; class TokenExpirationTest { @@ -51,26 +52,26 @@ class TokenExpirationTest { UUID userId = UUID.randomUUID(); User mockUser = new User(); mockUser.setId(userId); - + // Configure repository to return our user when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser)); - + // Call our test method that forces the isExpired check to be true InvalidCredentialsException exception = assertThrows( InvalidCredentialsException.class, () -> testService.testTokenExpiration(userId) ); - + // Verify we get the exact "Token expired" exception message - assertEquals("Token expired", exception.getMessage(), + assertEquals("Token expired", exception.getMessage(), "The exception message should be 'Token expired' when a token is expired"); } // This class extends AuthenticationService to allow us to test specific code paths private class TestAuthenticationService extends AuthenticationService { public TestAuthenticationService(UserService userService, - PasswordEncoder passwordEncoder, - OTPService otpService, + PasswordEncoder passwordEncoder, + OTPService otpService, JwtService jwtService) { super(userService, passwordEncoder, otpService, jwtService); } @@ -83,10 +84,10 @@ class TokenExpirationTest { .setSubject(userId.toString()) .setIssuedAt(new Date(System.currentTimeMillis() - 200000)) .setExpiration(new Date(System.currentTimeMillis() - 100000)); // Expired! - + // This is the exact code from the main method that checks expiration boolean isExpired = claims.getExpiration().before(new Date(System.currentTimeMillis())); - + if (isExpired) { throw new InvalidCredentialsException("Token expired"); } diff --git a/src/test/java/com/safetypin/authentication/service/UserServiceTest.java b/src/test/java/com/safetypin/authentication/service/UserServiceTest.java index 64dd562813fecb7c3eee0d4af5171c065b866798..de7810e54c91426a29f0b282f76fbbfa3a80da47 100644 --- a/src/test/java/com/safetypin/authentication/service/UserServiceTest.java +++ b/src/test/java/com/safetypin/authentication/service/UserServiceTest.java @@ -13,7 +13,8 @@ import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class UserServiceTest {