-
Notifications
You must be signed in to change notification settings - Fork 906
resolve #906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
resolve #906
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package mate.academy.dao; | ||
|
||
import java.util.Optional; | ||
import mate.academy.model.User; | ||
|
||
public interface UserDao { | ||
User add(User user); | ||
|
||
User get(Long id); | ||
|
||
Optional<User> findByEmail(String email); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package mate.academy.dao.impl; | ||
|
||
import java.util.Optional; | ||
import mate.academy.dao.UserDao; | ||
import mate.academy.exception.DataProcessingException; | ||
import mate.academy.model.User; | ||
import mate.academy.util.HibernateUtil; | ||
import org.hibernate.HibernateException; | ||
import org.hibernate.Session; | ||
import org.hibernate.Transaction; | ||
|
||
public class UserDaoImpl implements UserDao { | ||
@Override | ||
public User add(User user) { | ||
Session session = null; | ||
Transaction transaction = null; | ||
try { | ||
session = HibernateUtil.getSessionFactory().openSession(); | ||
transaction = session.beginTransaction(); | ||
session.persist(user); | ||
transaction.commit(); | ||
return user; | ||
} catch (Exception e) { | ||
if (transaction != null) { | ||
transaction.rollback(); | ||
} | ||
throw new DataProcessingException("can't save user to db" + user, e); | ||
} finally { | ||
if (session != null) { | ||
session.close(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public User get(Long id) { | ||
try (Session session = HibernateUtil.getSessionFactory().openSession()) { | ||
return session.get(User.class, id); | ||
} catch (Exception e) { | ||
throw new DataProcessingException("can't get user by id:" + id, e); | ||
} | ||
} | ||
|
||
@Override | ||
public Optional<User> findByEmail(String email) { | ||
try (Session session = HibernateUtil.getSessionFactory().openSession()) { | ||
return session.createQuery("FROM User u where u.email = :email", User.class) | ||
.setParameter("email", email) | ||
.uniqueResultOptional(); | ||
} catch (HibernateException e) { | ||
throw new DataProcessingException("can't find user by email " + email, e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package mate.academy.exception; | ||
|
||
public class AuthenticationException extends RuntimeException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
public AuthenticationException(String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package mate.academy.exception; | ||
|
||
public class RegistrationException extends RuntimeException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
public RegistrationException(String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package mate.academy.model; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
|
||
@Entity | ||
@Table(name = "users") | ||
public class User { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
@Column(unique = true) | ||
private String email; | ||
private String password; | ||
private byte[] salt; | ||
|
||
public User() { | ||
} | ||
|
||
public User(String email, String password) { | ||
this.email = email; | ||
this.password = password; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
|
||
public String getEmail() { | ||
return email; | ||
} | ||
|
||
public void setEmail(String email) { | ||
this.email = email; | ||
} | ||
|
||
public String getPassword() { | ||
return password; | ||
} | ||
|
||
public void setPassword(String password) { | ||
this.password = password; | ||
} | ||
|
||
public byte[] getSalt() { | ||
return salt; | ||
} | ||
|
||
public void setSalt(byte[] salt) { | ||
this.salt = salt; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "User{" | ||
+ "id=" + id | ||
+ ", email=" + email + '\'' | ||
+ '}'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package mate.academy.security; | ||
|
||
import mate.academy.exception.AuthenticationException; | ||
import mate.academy.exception.RegistrationException; | ||
import mate.academy.model.User; | ||
|
||
public interface AuthenticationService { | ||
User login(String email, String password) throws AuthenticationException; | ||
|
||
/** | ||
* We should register a new user. The new user entity will contain the email and password | ||
* @param email - user email. should be unique for each user | ||
* @param password - user password | ||
* @return new user instance | ||
*/ | ||
User register(String email, String password) throws RegistrationException; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package mate.academy.security; | ||
|
||
import java.util.Optional; | ||
import mate.academy.exception.AuthenticationException; | ||
import mate.academy.exception.RegistrationException; | ||
import mate.academy.lib.Inject; | ||
import mate.academy.lib.Service; | ||
import mate.academy.model.User; | ||
import mate.academy.service.UserService; | ||
import mate.academy.util.HashUtil; | ||
|
||
@Service | ||
public class AuthenticationServiceImpl implements AuthenticationService { | ||
@Inject | ||
private UserService userService; | ||
|
||
@Override | ||
public User login(String email, String password) throws AuthenticationException { | ||
Optional<User> userFromDbOptional = userService.findByEmail(email); | ||
if (userFromDbOptional.isEmpty()) { | ||
throw new AuthenticationException("Can't authenticate user " + email); | ||
} | ||
User user = userFromDbOptional.get(); | ||
String hashedPassword = HashUtil.hashPassword(password, user.getSalt()); | ||
if (user.getPassword().equals(hashedPassword)) { | ||
return user; | ||
} | ||
throw new AuthenticationException("Login or password is incorrect..."); | ||
} | ||
|
||
@Override | ||
public User register(String email, String password) throws RegistrationException { | ||
Optional<User> userFromDb = userService.findByEmail(email); | ||
if (userFromDb.isPresent() || email.isEmpty() || password.isEmpty()) { | ||
throw new RegistrationException("This email is already taken :" + email); | ||
Comment on lines
+34
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The registration method should hash the password before storing the user. Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message should be more descriptive. Consider specifying whether the email is taken or if the email/password is empty. |
||
} | ||
return userService.add(new User(email, password)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package mate.academy.service; | ||
|
||
import java.util.Optional; | ||
import mate.academy.model.User; | ||
|
||
public interface UserService { | ||
User add(User user); | ||
|
||
Optional<User> findByEmail(String email); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package mate.academy.service.impl; | ||
|
||
import java.util.Optional; | ||
import mate.academy.dao.UserDao; | ||
import mate.academy.lib.Inject; | ||
import mate.academy.model.User; | ||
import mate.academy.service.UserService; | ||
|
||
public class UserServiceImpl implements UserService { | ||
@Inject | ||
private UserDao userDao; | ||
|
||
@Override | ||
public User add(User user) { | ||
return userDao.add(user); | ||
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure that the user's password is hashed before calling |
||
} | ||
|
||
@Override | ||
public Optional<User> findByEmail(String email) { | ||
return userDao.findByEmail(email); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package mate.academy.util; | ||
|
||
import java.security.MessageDigest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.SecureRandom; | ||
|
||
public class HashUtil { | ||
private static final String CRYPTO_ALGORITHM = "SHA-512"; | ||
|
||
private HashUtil() { | ||
} | ||
|
||
public static byte[] getSalt() { | ||
SecureRandom securerandom = new SecureRandom(); | ||
byte[] salt = new byte[16]; | ||
securerandom.nextBytes(salt); | ||
return salt; | ||
} | ||
|
||
public static String hashPassword(String password, byte[] salt) { | ||
StringBuilder hashedPassword = new StringBuilder(); | ||
try { | ||
MessageDigest messageDigest = MessageDigest.getInstance(CRYPTO_ALGORITHM); | ||
messageDigest.update(salt); | ||
byte[] digest = messageDigest.digest(password.getBytes()); | ||
for (byte b : digest) { | ||
hashedPassword.append(String.format("%02x", b)); | ||
} | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new IllegalArgumentException("Couldn't create hash using SHA-512 algorithm", e); | ||
} | ||
return hashedPassword.toString(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider improving the error message by adding more context, such as the user details, to help with debugging. For example, include the user's email or ID if available.