package net.pechorina.kontempl.service;
import net.pechorina.kontempl.data.AuthToken;
import net.pechorina.kontempl.data.Credential;
import net.pechorina.kontempl.data.OptiUserDetails;
import net.pechorina.kontempl.data.User;
import net.pechorina.kontempl.repos.AuthTokenRepo;
import net.pechorina.kontempl.repos.CredentialRepo;
import net.pechorina.kontempl.repos.UserRepo;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Service
public class UserService {
static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Autowired
private UserRepo userRepo;
@Autowired
private CredentialRepo credentialRepo;
@Autowired
private AuthTokenRepo authTokenRepo;
@Autowired
private Environment env;
@Transactional
public AuthToken getCurrentAuthToken(String uuid) {
int tokenExpireMinutes = Integer.parseInt( env.getProperty("auth_token_expire") );
AuthToken a = authTokenRepo.findOne(uuid);
logger.debug("Token retrieved: " + a);
// check if it is not expired
if ( (a != null) && (a.getUpdated().plusMinutes(tokenExpireMinutes).isBeforeNow()) ) {
// expired
authTokenRepo.delete(uuid);
logger.debug("Token expired: " + a);
return null;
}
if (a != null) {
// update token
a.setUpdated(new DateTime());
return authTokenRepo.saveAndFlush(a);
}
return null;
}
// run every two hours
@Scheduled(fixedRate=7200000)
@Transactional
public void removeExpiredTokens() {
List<AuthToken> tokens = authTokenRepo.findAll();
int tokenExpireMinutes = Integer.parseInt( env.getProperty("auth_token_expire") );
List<AuthToken> expiredTokens = tokens.stream().filter(t -> t.getUpdated().plusMinutes(tokenExpireMinutes).isBeforeNow() ).collect(Collectors.toList());
int cnt = 0;
for(AuthToken t: expiredTokens) {
authTokenRepo.delete(t);
cnt++;
}
if (cnt > 0) {
logger.info("Removed " + cnt + " expired auth tokens.");
}
}
@Transactional
public AuthToken createNewAuthToken(User user, String ipAddress, String userAgent) {
AuthToken a = new AuthToken(user, ipAddress, userAgent);
return authTokenRepo.saveAndFlush(a);
}
@Transactional
public User saveNewUser(User u, String email, String password) {
if (( email != null) && (password != null)) {
String pwdHash = DigestUtils.sha1Hex(password);
String uid = "password:" + email;
Credential c = new Credential(u, "password", uid, email, pwdHash);
c.setVerified(true);
u.addCredential(c);
}
return userRepo.saveAndFlush(u);
}
@Transactional
public User getUserById(int id) {
return userRepo.findOne(id);
}
@Transactional
public User getUserByIdDetailed(int id) {
User u = userRepo.findOne(id);
retrieveDetails(u);
return u;
}
private void retrieveDetails(User u) {
if (u.getCredentials() != null) u.getCredentials().size();
if (u.getAuthTokens() != null) u.getAuthTokens().size();
if (u.getRoles() != null) u.getRoles().size();
}
@Transactional
public User getUserByEmail(String email) {
String uid = "password:" + email;
Credential c = credentialRepo.findByUid(uid);
if (c != null) {
User u = c.getUser();
int id = u.getId();
logger.debug("found user: " + id + " " + u.getName());
return u;
}
else {
return null;
}
}
@Transactional
public Credential getUserCredentialById(int id) {
return credentialRepo.findOne(id);
}
@Transactional
public List<User> findUsers() {
return userRepo.listActiveUsers();
}
@Transactional
public Set<Credential> getUserCredentials(Integer userId) {
User u = userRepo.findOne(userId);
int s = 0;
if (u.getCredentials() != null) {
s = u.getCredentials().size();
}
logger.debug("total credentials found: " + s);
return u.getCredentials();
}
@Transactional
public Credential getUserCredential(Integer userId, String authType) {
User u = userRepo.findOne(userId);
return u.getCredentials().stream().filter(cr -> cr.getAuthServiceType().equalsIgnoreCase(authType)).findFirst().orElse(null);
}
@Transactional
public Credential getCredential(Integer id) {
return credentialRepo.findOne(id);
}
@Transactional
public User save(User user) {
return userRepo.saveAndFlush(user);
}
@Transactional
public void delete(User user) {
userRepo.delete(user);
}
@Transactional
public void saveCredential(Credential entity) {
credentialRepo.saveAndFlush(entity);
}
@Transactional
public void deleteCredential(Credential entity) {
credentialRepo.delete(entity);
}
@Transactional
public List<AuthToken> listAuthTokens(User u) {
return authTokenRepo.findByUser(u);
}
@Transactional
public void deleteAuthToken(AuthToken token) {
authTokenRepo.delete(token);
}
@Transactional
public AuthToken getAuthToken(String uuid) {
return authTokenRepo.findOne(uuid);
}
@Transactional
public void updatePasswordEmailCredential(Credential c, String email, String password) {
String pwdHash = DigestUtils.sha1Hex(password);
String uid = "password:" + email;
c.setEmail(email);
c.setUid(uid);
c.setAuthData(pwdHash);
credentialRepo.saveAndFlush(c);
}
@Transactional
public boolean checkIfEmailAvailable(String email) {
String uid = "password:" + email;
Credential c = credentialRepo.findByUid(uid);
return c == null;
}
public void setUserSession(HttpServletRequest request, User user) {
UserDetails ud = new OptiUserDetails(user, user.getRoles());
UsernamePasswordAuthenticationToken t = new UsernamePasswordAuthenticationToken(ud, null, ud.getAuthorities());
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(t);
// Create a new session and add the security context.
HttpSession session = request.getSession(true);
synchronized (session.getId()) {
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}
}
}