diff --git a/ass2-service/auth/src/main/java/dst/ass2/service/auth/impl/CachingAuthenticationService.java b/ass2-service/auth/src/main/java/dst/ass2/service/auth/impl/CachingAuthenticationService.java new file mode 100644 index 0000000..487f8f8 --- /dev/null +++ b/ass2-service/auth/src/main/java/dst/ass2/service/auth/impl/CachingAuthenticationService.java @@ -0,0 +1,108 @@ +package dst.ass2.service.auth.impl; + +import dst.ass1.jpa.dao.impl.DAOFactory; +import dst.ass1.jpa.model.IRider; +import dst.ass2.service.api.auth.AuthenticationException; +import dst.ass2.service.api.auth.NoSuchUserException; +import dst.ass2.service.auth.ICachingAuthenticationService; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static java.lang.String.format; + +@Named("ICachingAuthenticationService") +@Singleton +public class CachingAuthenticationService implements ICachingAuthenticationService { + @PersistenceContext + private EntityManager entityManager; + @Resource + private DAOFactory daoFactory; + + private final ConcurrentHashMap userCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap tokenCache = new ConcurrentHashMap<>(); + + @Transactional + @Override + public void changePassword(String email, String newPassword) throws NoSuchUserException { + IRider rider = daoFactory.createRiderDAO().findByEmail(email); + if (rider == null) + throw new NoSuchUserException("Could not find user with email " + email); + byte[] hashedPw = generateSHA1(newPassword); + rider.setPassword(hashedPw); + entityManager.merge(rider); + userCache.replace(email, hashedPw); + } + + @Override + public String getUser(String token) { + return tokenCache.get(token); + } + + @Override + public boolean isValid(String token) { + return tokenCache.containsKey(token); + } + + @Override + public boolean invalidate(String token) { + return tokenCache.remove(token) != null; + } + + @Transactional + @Override + public String authenticate(String email, String password) throws NoSuchUserException, AuthenticationException { + // Check if user in cache + if (!userCache.containsKey(email)) { + IRider rider = daoFactory.createRiderDAO().findByEmail(email); + if (rider == null) + throw new NoSuchUserException("Could not find user with email " + email); + userCache.put(email, rider.getPassword()); + } + byte[] currentPassword = userCache.get(email); + byte[] newPassword = generateSHA1(password); + + if (!Arrays.equals(currentPassword, newPassword)) { + throw new AuthenticationException("Failed to authenticate: Passwords do not match"); + } + String token = UUID.randomUUID().toString(); + tokenCache.put(token, email); + return token; + } + + @PostConstruct + @Override + public void loadData() { + for (IRider rider : daoFactory.createRiderDAO().findAll()) { + userCache.putIfAbsent(rider.getEmail(), rider.getPassword()); + } + } + + @Override + public void clearCache() { + userCache.clear(); + } + + private byte[] generateSHA1(String string) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + digest.update(string.getBytes()); + return digest.digest(); + } +}